Cloud Continuous Integration
현대의 개발 업무는 단 한 사람에 의해 진행되는 것이 아니라 협업을 통해서 이루어집니다. 이를 기반으로 Git과 같은 고도의 버전 관리 시스템이 등장하였으며, 이러한 기술을 바탕으로 지속적 통합 (CI)이라는 개발 프로세스가 정립되었습니다. 지속적 통합은 서비스의 전달에 앞서 선행되어야 하는 과정이며, 또한 사람의 실수를 줄이는 자동화의 과정이기도 합니다.
이번 시간에는 지속적 통합의 과정을 이해하고 각 단계에서 행하는 일들이 무엇인지 알아봅니다. 또한 작은 애플리케이션을 하나의 배포 가능한 형태(artifact)로 만들기 위해, CI 도구를 이용해서 Workflow를 작성하는 실습을 진행할 것입니다.
학습 목표
- 지속적 통합의 필요성을 설명할 수 있다.
- 지속적 통합 개념이 나오게 된 배경을 이해할 수 있다.
- 지속적 통합의 장점을 설명할 수 있다.
- 빌드의 개념을 이해할 수 있다.
- CI 도구를 이용하여 지속적 통합이 이루어지는 과정을 직접 구현할 수 있다
- 다양한 CI 도구의 차이점을 이해할 수 있다.
빌드(Build)
빌드란?
소프트웨어 개발에서 빌드(build)란, 소스 코드 파일들을 컴퓨터가 이해할 수 있는 실행 가능한 소프트웨어 산출물로 변환하는 과정을 말합니다. 이 산출물은 일반적으로 아티팩트(Artifact)라고 부르며 바이너리 파일, 라이브러리, 패키지 등의 형태로 제공됩니다. 빌드 과정에서는 소스 코드 파일들을 컴파일하고, 링크하고, 패키징하고, 배포할 수 있는 형태로 변환합니다.
빌드 도구의 필요성
빌드 과정은 매우 복잡하고 번거로운 일이며, 수동으로 이루어지면 매우 오래 걸리고 실수할 가능성이 높습니다. 또한 프로젝트가 커지면 커질수록 빌드 과정에서 필요한 작업들이 복잡해지고, 빌드 도구 없이는 이를 관리하기가 매우 어렵습니다. 따라서 빌드 도구를 사용하여 빌드 과정을 자동화하고, 더 효율적이고 안정적인 소프트웨어 릴리스를 위한 과정을 간소화할 수 있습니다.
대표적 빌드 도구 소개
언어별로 대표적인 빌드 도구가 존재합니다.
- Java : Maven, Gradle
- Python : (의존성 관리 및 빌드 스크립트 실행 도구) pip, setuptools
- JavaScript : (의존성 관리 및 빌드 스크립트 실행 도구) npm, yarn
- C++ : CMake, Makefile
이들 빌드 도구는 각 언어의 특성에 맞게 설계되었으며, 각각의 장단점이 있으므로 사용 시 고려해야 할 사항들이 있습니다.
빌드 도구 선택 시 고려사항
빌드 도구를 선택할 때는 라이브러리 관리, 빌드 스크립트 작성 용이성, 확장성 등을 고려해야 합니다.
라이브러리 관리는 빌드 도구에서 자동으로 의존성을 해결할 수 있는 기능을 제공하고, 빌드 스크립트 작성 용이성은 빌드 도구의 문법과 구성이 개발자에게 친숙한지 여부를 고려해야 합니다. 확장성은 빌드 도구가 대규모 프로젝트에서도 충분히 확장 가능한 구조를 가지고 있는지 여부를 고려해야 합니다.
참고: 빌드와 테스트의 불편함과 어려움에서 시작
지속적 통합(Continuous Integration)은 소프트웨어 개발에서 매우 중요한 개념 중 하나입니다. 이는 코드 변경 사항이 발생할 때마다 자동으로 빌드 및 테스트를 실행하여, 코드 변경 사항이 문제를 일으키지 않는지 확인하는 것을 말합니다.
만약 지속적 통합 과정이 자동으로 작동하도록 구성되어 있지 않다면, 개발자가 수동으로 빌드 및 테스트를 실행해야 합니다. 이는 시간이 오래 걸리고, 실수를 유발할 가능성이 높습니다. 또한, 수동으로 실행하면서 생기는 인적 오류(Human Error)로 인해 문제가 발생할 가능성도 높아집니다.
따라서 지속적 통합을 구성하면, 개발자는 자동으로 빌드 및 테스트를 실행하여 문제를 빨리 감지하고, 더욱 안정적인 소프트웨어를 개발할 수 있습니다. 또한, 지속적 통합을 구성하여, 여러 개발자가 동시에 작업하더라도, 각자의 코드 변경 사항이 다른 개발자들의 코드 변경 사항과 충돌하는 문제를 사전에 감지할 수 있습니다.
지속적 통합 (CI : Continuous Integration) 개요
[이미지] 전체 CI/CD 과정 중 지속적 통합(CI) 과정 (빨간색 표기)
지속적 통합 (CI : Continuous Integration)
지속적 통합(CI)은 개발자들이 새로운 코드를 작성하고 이전 코드와 함께 자동으로 빌드하고 테스트를 수행하는 프로세스로 매우 중요한 개발 방법론 중 하나입니다. CI는 다음과 같은 이점이 있습니다.
- 코드 품질 향상: CI는 코드를 자동으로 빌드하고 테스트하므로 개발자들은 실수를 줄일 수 있습니다. 이는 코드 품질 향상에 큰 도움이 됩니다.
- 더 빠른 피드백: CI는 새로운 코드를 작성하고 이전 코드와 함께 자동으로 빌드하고 테스트하므로, 문제가 발생하면 빠르게 발견할 수 있습니다. 이는 더 빠른 피드백을 받을 수 있게 해줍니다.
- 더 높은 효율성: CI는 빌드 및 테스트를 자동화하므로, 개발자들은 수동으로 작업하는 시간을 절약하고 더 많은 시간을 실제 개발에 할애할 수 있습니다.
CI를 사용하면 개발자들은 더 많은 코드를 더 빠르게 개발할 수 있으며, 코드의 품질도 향상시킬 수 있습니다. 이러한 이유로 CI는 현재 많은 기업에서 사용되고 있으며, 개발자들에게 매우 중요한 개발 방법론 중 하나입니다.
지속적 통합의 원칙
지속적 통합은 개발자들이 코드를 작성하면 이전 코드와 함께 자동으로 빌드하고 테스트하는 방법입니다. 이를 통해 코드 품질을 향상하고 더 빠른 피드백을 받을 수 있으며, 더 높은 효율성을 얻을 수 있습니다.
지속적 통합의 원칙은 매우 간단합니다. 새로운 코드가 작성되면, 이전 코드와 함께 자동으로 빌드 및 테스트를 수행하고, 문제가 없으면 코드를 릴리스합니다. 이렇게 하면 개발자들은 더 많은 코드를 더 빠르게 개발할 수 있으며, 코드 품질도 향상할 수 있습니다.
더 구체적으로, CI는 다음과 같은 프로세스를 따릅니다.
- 버전 관리 시스템에서 새로운 코드가 등록되면, CI 서버에서 자동으로 빌드 및 테스트를 진행합니다.
- 빌드 및 테스트가 완료되면, 결과를 개발자들에게 알려줍니다.
- 문제가 발생한 경우, 개발자들은 이를 빠르게 수정할 수 있습니다.
- 문제가 없으면, 코드를 릴리스합니다.
이러한 과정을 통해 개발자들은 더 높은 효율성을 얻을 수 있으며, 코드 품질도 향상할 수 있습니다. 이러한 이유로 많은 기업에서 CI를 사용하고 있습니다.
지속적 통합 (CI : Continuous Integration) 도구
CI / CD를 위한 정말 많은 Tool이 존재합니다. 그중 CI에 특화되어있는 Jenkins, Travis CI, Github ActionS에 대해 학습합니다.
Jenkins 🔗 공식 사이트
[이미지] Jenkins 공식 로고
공식 문서는 Jenkins를 다음과 같이 설명하고 있습니다.
Jenkins는 소프트웨어 구축, 테스트, 제공 또는 배포와 관련된 모든 종류의 작업을 자동화하는 데 사용할 수 있는 독립형 오픈 소스 자동화 서버입니다.
Jenkins는 기본 시스템 패키지, Docker를 통해 설치하거나 JRE(Java Runtime Environment)가 설치된 시스템에서 독립 실행형으로 실행할 수도 있습니다.
특징
- 설치형: 별도의 서버가 필요합니다.
- 다양한 플러그인을 활용할 수 있습니다.
- 쿠버네티스, Docker 등과 호환됩니다.
- 다양한 운영체제에서 사용이 가능합니다.
Travis CI 🔗 공식 사이트
[이미지] Travis CI 공식 로고
Wikipedia에 따르면 Travis CI는 다음과 같이 설명할 수 있습니다.
Travis CI는 호스트형(hosted) 배포 자동화 서비스로, GitHub 및 Bitbucket 등에서 호스팅되는 소프트웨어 프로젝트를 빌드하고 테스트하는 데 사용됩니다.
특징
- 클라우드 서비스(SasS) 형태로 사용할 수 있습니다.
- Travis 자체에서 호스팅을 해주기 때문에 관리적인 측면에서 편리합니다.
- Clojure, Erlang, Groovy Haskell, Java, JavaScirpt, Node.js, Perl PHP, Rython, Ruby 등의 다양한 언어를 지원합니다.
GitHub Actions 🔗 공식 사이트
[이미지] Github Actions 공식 로고
공식 문서는 Github Actions를 다음과 같이 설명하고 있습니다.
GitHub Actions는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 지속적 통합 및 지속적 배포(CI/CD) 플랫폼입니다. 리포지토리에 대한 모든 풀 요청을 빌드 및 테스트하는 워크플로를 생성하거나 병합된 풀 요청을 프로덕션에 배포할 수 있습니다. GitHub Actions는 DevOps를 넘어 리포지토리에서 다른 이벤트가 발생할 때 워크플로를 실행할 수 있습니다. GitHub는 Linux, Windows 및 macOS 가상 머신을 제공하여 워크플로를 실행하거나 자체 데이터 센터 또는 클라우드 인프라에서 자체 호스팅 러너를 호스팅할 수 있습니다.
특징
- GitHub 저장소를 기반으로 소프트웨어 개발 Workflow를 자동화할 수 있는 툴입니다.
- GitHub 마켓 플레이스를 통해 여러 사람이 공유한 Workflow를 찾을 수 있으며, 자신이 직접 만들어 공유할 수도 있습니다.
- 공개 저장소(Github Public Repository)는 무료로 사용할 수 있으며, 비공개 저장소(Github Private Repository) 같은 경우 매달 일정량의 무료 사용량 이후에 요금이 부과됩니다.
- 한 달에 500MB 스토리지와 실행 시간 2,000분(minute)까지 제공됩니다. (참고)
- Github Actions 레퍼런스: Learn GitHub Actions - GitHub Docs
실습 - Github Actions를 통한 컨테이너 지속적 통합
Github Actions를 통한 컨테이너 지속적 통합
지속적 통합(CI : Continuous Intergration)의 대표 도구 중 하나인 Github Actions를 사용하여 간단한 SpringBoot 웹 애플리케이션을 도커 이미지로 만들어 도커 이미지 저장소에 배포(Push)하는 지속적 통합 실습을 진행합니다.
Github Actions를 통한 컨테이너 지속적 통합 실습 흐름
[그림] Github Actions를 통한 컨테이너 지속적 통합 실습 흐름
- 백엔드 개발자의 IDE(e.g. 로컬 환경의 IntelliJ)에서 코드 작업 후 연결된 Github 저장소로 Commit & Push합니다.
- Github Repository에 변화가 감지되면 Github Actions가 작동합니다.
- 작성한 Github Actions Workflow의 순서대로 명령이 실행됩니다.3-2. Repository에 있는 Dockerfile을 통해 웹 애플리케이션을 도커 이미지로 만듭니다.
- 3-1. Github Repository에 갱신된 코드에 테스트 및 빌드를 진행합니다. (./gradlew build를 명령한 것과 같습니다.)
- Github Actions Workflow에 의해 (3-2)에서 생성된 이미지가 DockerHub에 업로드됩니다.
실습 개요 및 사전 준비 사항
실습 시작 전 사전 준비
Github Public Repository 준비
Github Actions를 사용하기 위해선 Github Repository가 필요합니다. 이때 공개 리포지토리(Public Repository)는 무료로, 비공개 리포지토리(Private Repository)는 부분 유료로 사용이 가능합니다.
실습을 위해 공개 리포지토리를 생성하겠습니다.
Github에 로그인한 후 Repositories 메뉴 > New 버튼을 클릭합니다.
Owner는 개인 계정을 선택하고, Repository name에는 적절한 이름을 작성합니다. 이때 생성할 리포지토리는 반드시 Public을 선택해 공개 리포지토리를 생성합니다.
Github Secret 설정
Github Actions는 중요한 정보를 NAME : VALUE 쌍으로 구성된 Github Secret이라는 환경변수에 별도 저장하여 관리할 수 있습니다. Github Secret에 도커 이미지 저장소에 접근하기 위한 계정 정보를 설정합니다.
[그림] Github Actions 환경 변수 등록
사용될 Github 저장소로 이동한 뒤 Settings → Secrets and Variables → Actions 로 이동합니다.
화면 오른쪽에 있는 New Repository secret 버튼을 눌러 도커 이미지 저장소 계정 정보를 다음과 같이 두 개 만듭니다.
- DOCKER_HUB_USERNAME : 도커 유저네임
- DOCKER_HUB_PASSWORD : 도커 비밀번호
완료되면 다음과 같이 두 개 환경 변수 등록이 완료됩니다.
[그림] Github Actions 환경 변수 등록 완료 화면
도커 계정 정보 외에도 많은 환경 변수가 필요할 수 있습니다. 필요한 환경 변수는 이와 같이 관리할 수 있습니다.
실습 코드 준비
https://start.spring.io/ 를 통해 간단한 프로젝트를 생성합니다. 이번 실습에선 간단히 “Hello World” 정도만 확인할 수 있는 SpringBoot 웹 애플리케이션 정도가 필요합니다. 아래 설명과 이미지를 참고하여 애플리케이션을 준비하기 바랍니다.
- 버전의 경우 아래의 이미지와 완전히 동일하진 않을 수 있습니다. SNAPSHOT이 표기되어있지 않은 2.X.X를 선택합니다. (이미지는 2023년 6월 기준)
- Artifact, Name, Description 등의 값은 적절한 값을 입력합니다.
- Spring Web 의존 모듈을 선택합니다.
프로젝트를 생성했다면 웹 애플리케이션 실행 여부를 쉽게 확인할 수 있도록 간단한 컨트롤러를 작성합니다.
생성한 Github 리포지토리에 웹 애플리케이션을 업로드합니다. 명령어의 실행 위치는 웹 애플리케이션의 build.gradle이 있는 애플리케이션 디렉터리 최상위 위치입니다.
$ echo "# My Repository" >> README.md
$ git init
$ git add .
$ git commit -m "first commit"
$ git branch -M main
$ git remote add origin {웹 애플리케이션을 업로드 하려는 Github 리포지토리 url}
$ git push -u origin main
Github Actions를 통한 컨테이너 지속적 통합
지속적 통합(CI : Continuous Intergration)의 대표 도구 중 하나인 Github Actions를 사용하여 간단한 SpringBoot 웹애플리케이션을 도커 이미지로 만들어 도커 이미지 저장소에 배포(Push)하는 지속적 통합 실습을 진행합니다.
로컬 환경 IDE에서 코드 작업 후 연결된 Github 저장소로 Commit & Push 하면 Github Actions를 통해 갱신된 코드가 자동으로 빌드되고 테스트를 진행한 후 웹 애플리케이션을 도커 이미지로 생성하여 도커 이미지 저장소에 배포하는 과정을 자동으로 수행합니다. 이러한 처리 프로세스를 설정하는 과정을 알아봅니다.
지속적 통합을 위한 몇 가지 사전 준비물이 필요합니다.
- IntelliJ IDE
- Public Github Repository
- Docker Hub Repository
- Docker가 설치된 컴퓨터
- Hello World를 출력할 수 있는 간단한 SpringBoot 웹 애플리케이션
SpringBoot 프로젝트 Gradle 설정
2.X.X 버전의 SpringBoot는 빌드(./gradlew build)할 때 {file_name}.jar와 {file_name}-plain.jar 두 개의 파일이 생성됩니다. 두 개 파일이 생성되면 지속적 통합의 연속 작업 중 도커 이미지를 생성하는 과정에서 어떤 JAR 파일로 생성할지에 대한 문제가 발생하기 때문에 지속적 통합 작업 도중에 실패가 발생합니다. 따라서 Gradle 설정에서 -plain이 붙은 JAR 파일 생성 기능을 비활성화하여 미리 방지합니다.
jar {
enabled = false
}
Dockerfile 생성
Gradle 빌드 다음 단계인 SpringBoot 웹 애플리케이션을 도커 컨테이너로 배포하기 위해 도커 이미지를 만드는 과정에 필요한 작업입니다.
Dockerfile을 만들고 파일 안에 도커 이미지를 만드는 과정을 작성합니다. 도커 이미지를 빌드할 때 작성해 둔 Dockerfile의 내용을 바탕으로 생성합니다.
프로젝트 내 build.gradle 파일이 위치한 경로인 프로젝트 최상위 경로에 Dockerfile 이라는 파일을 생성하고 아래 내용을 입력합니다. (대소문자 구분)
[그림] Dockerfile의 위치
# (1) base-image
FROM openjdk:11
# (2) COPY에서 사용될 경로 변수
ARG JAR_FILE=build/libs/*-SNAPSHOT.jar
# (3) jar 빌드 파일을 도커 컨테이너로 복사
COPY ${JAR_FILE} app.jar
# (4) jar 파일 실행
ENTRYPOINT ["java","-jar","/app.jar"]
✔️ Dockerfile 코드 설명
Dockerfile에는 도커 이미지를 만들기 위한 과정이 작성되어 있습니다.
어떤 과정이 필요한지 알아보겠습니다.
(1) FROM openjdk:11
Dockerfile로 이미지를 만들 땐 베이스가 되는 이미지를 기반으로 새로운 이미지를 만들게 됩니다. 우리는 SpringBoot 웹 애플리케이션을 만들기 위해 openjdk 11의 이미지를 사용합니다.
운영체제, 웹서버 등 다양한 이미지가 Docker Hub 공식 계정을 통해 제공되고 있으며 이미지를 만드는 환경이나 버전에 따라 다양한 베이스 이미지를 선택할 수 있습니다.
(2) ARG JAR_FILE=build/libs/*.jar
ARG 명령어를 이용하면 Dockerfile 내에서 변수를 등록할 수 있습니다.
Github Actions를 이용해 빌드한 결과물(jar파일)에 쉽게 접근하기 위해, 경로를 포함해 JAR_FILE이라는 이름의 변수에 저장합니다.
(3) COPY ${JAR_FILE} app.jar
COPY A B 명령어는 A에서 B로 이동하는 리눅스의 cp명령어와 비슷합니다. Dockerfile에서는 A는 Dockerfile이 있는 환경에서의 경로 혹은 파일이 컨테이너의 경로 혹은 파일로 복사됩니다. 사이사이 띄어쓰기를 꼭 유의해 주세요.
실습 코드의 COPY ${JAR_FILE} app.jar 는 JAR_FILE에 저장된 값을 적용하면 **COPY build/libs/*.jar app.jar** 로 작성할 수 있습니다. 즉 build/libs/*.jar를 컨테이너에 복사하되 app.jar라는 이름으로 복사하라는 명령어입니다.
위와 같이 작성하면 컨테이너로 옮겨진 jar 파일은 기존에 어떤 이름이더라도 컨테이너에선 app.jar라는 이름으로 확인할 수 있습니다.
(4) ENTRYPOINT ["java","-jar","/app.jar"]
ENTRYPOINT를 이용해 컨테이너가 시작된 후 어떤 동작을 할지 정해 놓을 수 있습니다. 명령은 JSON 배열(e.g. [”a”, “b”, “c”])의 형태로 작성해야 합니다.
즉, 이 Dockerfile로 만든 이미지를 컨테이너로 실행하면 java -jar /app.jar가 실행된다는 뜻입니다. 별도의 jar 파일 실행 명령어 없이 컨테이너를 실행하면서 바로 SpringBoot 웹 애플리케이션을 실행할 수 있게 되는 거죠.
이번 실습에서 사용한 명령어 외에 다른 Dockerfile 문법이 궁금하다면 Dockerfile 공식문서를 참고하기 바랍니다.
Github Actions Workflow 작성
Workflow를 작성하기 전에 아직 프로젝트를 Github에 Push하지 않았다면 프로젝트 최상위 경로에 .github/workflows 디렉터리를 생성합니다. 그리고 그 밑에 main.yml이란 파일을 생성합니다. 이 파일에 Github Actions에서 수행될 동작을 작성합니다.
[그림] Github Actions Workflow의 위치
이제 main.yml 파일 안에 아래 내용을 작성합니다.
name: Java CI with Gradle
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'zulu'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Docker build
run: |
docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} -p ${{ secrets.DOCKER_HUB_PASSWORD }}
docker build -t spring-cicd .
docker tag spring-cicd {도커 유저네임}/spring-cicd:${GITHUB_SHA::7}
docker push {도커 유저네임}/spring-cicd:${GITHUB_SHA::7}
[코드]Github Actions를 위한 main.yml
각 옵션에 대한 설명은 다음과 같습니다.
- on: 이벤트를 트리거하는 조건을 지정합니다. 여기서는 push 이벤트가 main 브랜치에 발생할 때 작업이 실행됩니다.
- jobs: 하나 이상의 작업을 정의합니다.
- build: 작업의 이름입니다.
- runs-on: 작업을 실행하는 머신의 운영체제를 지정합니다.
- steps: 작업을 수행하기 위해 실행되는 일련의 단계를 정의합니다. 각 단계는 name과 run으로 구성됩니다.
- name: 작업에 대한 이름을 지정합니다.
- use: Github Actions의 마켓플레이스에 등록된 작업을 실행합니다. Github Actions에서 특정 작업을 일종의 라이브러리처럼 마켓플레이스에 등록해 놓을 수 있습니다.
- run: 해당 단계가 실행될 때 수행할 명령을 지정합니다.
steps의 하위 -name은 하나의 작업이라고 볼 수 있습니다. 각각 Set up JDK, Grant Execute permission for gradlew, Docker build 총 세 개의 작업으로 구성되어 있습니다. 작업은 작성된 순서대로 진행됩니다.
- Set up JDK
- 코드를 빌드하기 위해 JDK를 설정하고 점검합니다.
- Grant Execute permission for gradlew
- 코드를 gradle로 빌드합니다.
- Docker build
- 빌드 완료된 JAR 파일을 run에 기입된 명령대로 수행합니다.
- Dockerfile을 이용해 도커 이미지로 만든 후 이미지를 DockerHub에 배포(Push)합니다.
- DOCKER_HUB_USERNAME과 DOCKER_HUB_PASSWORD는 도커 이미지 저장소에 로그인하기 위해 필요한 계정 정보입니다. Github Secret에 등록한 환경변수를 읽어와 로그인합니다.
- DockerHub의 본인 계정에 spring-cicd라는 이름의 리포지토리가 없다면 자동으로 생성되어 업로드됩니다.
- 빌드 완료된 JAR 파일을 run에 기입된 명령대로 수행합니다.
지속적 통합 테스트
이제 지속적 통합을 위한 준비는 끝났습니다.
Commit & Push를 통해 Github에 반영되는 시점부터 코드를 검사하고 빌드하고 도커 이미지를 만든 후 생성된 도커 이미지를 도커 이미지 저장소에 등록하는 과정까지 자동으로 진행됩니다.
즉, 여러 단계의 과정을 지속적, 연속적으로 통합하는 셈입니다. 지속적 통합의 성공 여부를 확인하려면 아래 과정대로 테스트할 수 있습니다.
- 코드를 Github 저장소에 Commit & Push 합니다.
- Github 저장소에서 Actions 메뉴로 이동하면 아래 이미지처럼 진행 과정을 로그로 확인할 수 있습니다. 성공 실패 여부를 알 수 있습니다.
[그림] Github Actions의 수행 과정을 살펴보는 화면
Github Actions의 수행 결과가 성공적이라면 도커 이미지 저장소로 이동하여 아래 이미지처럼 지속적 통합작업으로 생성된 도커 이미지가 등록되었는지 확인합니다.
Github Actions의 build가 처음 성공하게 되면 Tags 정보는 1개만 존재하게 된다.
[그림] Docker Hub에 빌드한 도커 이미지가 등록된 모습
GIthub Actions 다시 실행(Re-Run)하기
코드가 아닌 Github Secret의 설정 단계에서 문제가 발생한 경우, 리포지토리에 코드를 다시 업로드 할 필요 없이 Github Actions을 다시 실행합니다.
- 가장 최근 실행된 workflow를 선택합니다.
[이미지] Github Actions의 가장 최근에 실행된 workflow 선택
오른쪽 상단의 Re-run all jobs를 클릭하면 뜨는 작은 창에서 [Re-run jobs]버튼을 클릭하면 Github Actions Workflow가 다시 실행됩니다.
[이미지] Re-run all jobs 버튼을 클릭하여 workflow 재실행
클라우드 환경에서 컨테이너 배포
클라우드 환경에서 도커 컨테이너 배포를 위한 사전 준비 사항
배포할 도커 이미지 준비
클라우드 환경에서 도커 컨테이너를 배포하기 위해선 개인 도커 허브 리포지토리에 하나 이상의 이미지가 업로드 되어있어야 합니다.
[그림] Docker Hub에 도커 이미지가 등록된 모습
아래 실습은 spring-cicd라는 이름의 리포지토리를 기준으로 작성되었습니다.
[그림] 실습 콘텐츠의 기준이 되는 리포지토리 이름
클라우드 환경에 도커 설치
배포하려는 클라우드 환경에 도커가 설치되어 있어야 합니다. 예를 들어 AWS의 EC2를 이용해 배포하려고 할 때 도커 설치가 필요한 환경은 EC2가 됩니다.
사용하려는 EC2를 선택한 후 세부 정보에서 운영체제 및 버전을 확인합니다.
[그림] EC2 인스턴스의 운영체제 확인
Ubuntu 플랫폼을 사용 중인 EC2 인스턴스의 경우 아래 링크를 참고하여 도커를 설치할 수 있습니다.
설치가 완료되면 터미널에 docker -v 명령어를 입력하면 설치 확인을 할 수 있습니다.
[그림] 도커 설치 확인
수동으로 도커 컨테이너 배포하기
먼저 배포될 웹 애플리케이션 컨테이너가 정상적으로 작동하는지 살펴봅니다.
sudo docker pull {도커 유저네임}/spring-cicd:{최신 버전의 태그}
위 명령어를 이용해 배포하려는 최신 도커 이미지를 배포 대상 서버에 내려받습니다.
[그림] 정상적으로 내려받은 도커 이미지 확인
도커 이미지가 올바르게 Pull 되었다면 위 이미지와 같이 도커 이미지 목록에 나타납니다. 이제 내려받은 도커 이미지의 태그를 변경하여 이 도커 이미지가 최신 버전의 도커 이미지라는 선언을 함과 동시에 도커 이미지 이름 또한 특정 도커 허브 계정을 붙이지 않은 상태로 만듭니다.
sudo docker tag {도커 유저네임}/spring-cicd:{TAG} spring-cicd
[그림] docker tag로 변경된 도커 이미지 확인
명령어가 정상적으로 작동하면 위 이미지처럼 spring-cicd의 latest 태그가 붙은 도커 이미지가 하나 더 추가됩니다. 서비스를 배포하는 것은 여러 문제점이 해결되고 신규 기능이 추가된 최신 버전이 배포된다는 의미이므로 배포될 최신 버전의 도커 이미지를 latest로 정의하여 배포합니다.
이제 최신 버전의 도커 이미지를 실행하여 컨테이너로 등록합니다.
sudo docker run -d --name server -p 8080:8080 spring-cicd
d 옵션을 사용하여 백그라운드에서 컨테이너가 동작하도록 설정했고, 포트는 8080을 사용한다고 정의했습니다. 컨테이너 생성과 시작 후 실행 중인 도커 컨테이너를 확인합니다.
sudo docker ps
[그림] 컨테이너 정상 동작 확인
위 이미지처럼 도커 컨테이너가 정상적으로 동작하고 있는 것이 확인된다면 서비스 배포가 되었다고 볼 수 있습니다.
만약 run을 했을 때 도커 컨테이너는 생성 되었지만 애플리케이션이 실행되지 않는다면 SpringBoot 웹 애플리케이션에 문제가 발생하여 웹 애플리케이션이 정상 기동되지 않아 컨테이너가 종료되었을 확률이 높으므로 개발 IDE에서 웹 애플리케이션을 디버그 해야 합니다. 그 외 다양한 문제가 발생할 수 있으므로 상황에 맞는 해결 방법이 필요합니다.
[그림] Post-man에서 정상적으로 출력된 “Hello World!!”
이제 Post-man과 같은 프로그램을 사용하여 EC2의 도메인(8080번 포트 포함)에서 “Hello World!!”가 잘 호출되는지 확인합니다.