티스토리 뷰

 

[Docker] Docker Swarm Service

스웜 모드 서비스 개념 Docker Swarm 모드를 사용하지 않고, 사용하는 도커 명령어의 제어 단위는 컨테이너이다. 예를 들어 docker run 명령어는 컨테이너를 생성하고, docker rm 명령어는 컨테이너를 삭

jojaeng2.tistory.com

이전에 Docker Swarm Service를 생성하고 사용해 봤다. Docker Swarm은 사용법이 어렵지 않아 3대의 서버에 Cluster를 쉽게 구축할 수 있었지만, 서비스가 업데이트돼야 할 때마다 매번 manager 노드로 가서 업데이트하는 작업이 귀찮다고 느껴졌고 CI/CD 파이프라인을 구축하기로 결정했다.

큰 흐름은 아래의 그림과 같다.

Worker Node에 대한 설정은 이전 글에 있으니 넘어가도록 하겠다. 

Web Application 만들기

먼저 테스트를 위한 간단한 애플리케이션을 만들자.

 

GitHub - jojaeng2/Docker-Swarm-practice

Contribute to jojaeng2/Docker-Swarm-practice development by creating an account on GitHub.

github.com

아주 간단한, 하나의 컨트롤러를 가지는 Springboot Application을 만들었다. 코드는 아래와 같다.

package docker.swarm.test.controller;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;

@RestController
public class MainController {


  @GetMapping("/hello")
  public String getRequest() {
    System.out.println("Hello");
    return "Hello world!";
  }
}

이제 이 코드를 Github에 Push하면, Build를 하고, Docker hub에 image를 Push 하는 CI 작업을 수행할 것이다.
항상 신뢰할 수 있는 코드만이 Docker hub에 존재하도록 하기 위해 테스트 코드 커버리지가 일정 수준보다 낮으면 빌드되지 않도록 막아주는 JaCoCo와 같은 라이브러리를 함께 사용하는 것도 방법이다. JaCoCo를 사용하는 방법은 이전에 정리한 적이 있다.

 

JaCoCo를 사용해 Code Coverage 관리하기

실제 서비스를 배포하고, 운영하면 문제가 생기기 마련이다. 이 문제를 사전에 막기 위해서는 테스트 코드가 큰 영향을 주는데 테스트 코드는 작성하기도 귀찮고 안일해지게 되는것 같다. 테스

jojaeng2.tistory.com

Github Actions 작성하기

이제 코드가 Push되면 동작할 Github Actions를 생성해 보자.

name: Java CI with Gradle

on:
  push:
    branches: [ "master" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'
    - name: Grant execute permission for gradlew
      run: chmod +x ./gradlew
    - name: Build with Gradle
      run: ./gradlew build
        
    - name: Login to DockerHub
      uses: docker/login-action@v1
      with:
        username: ${{secrets.DOCKERHUB_USERNAME}}
        password: ${{secrets.DOCKERHUB_TOKEN}}
        
    - name: Build the Docker image
      run: docker build --platform amd64 --build-arg DEPENDENCY=build/dependency -t ds4ouj/test-app --platform linux/amd64 .
    
    - name: Docker Push
      run: docker push ${{secrets.DOCKERHUB_USERNAME}}/test-app

master branch에 코드가 Push 되면 수행할 actions들을 작성했다. steps는 아래와 같다.

  1. JDK setup
  2. gradle 파일 권한 부여
  3. gradle 빌드
  4. Docker hub 로그인
  5. Docker image 생성
  6. Docker image를 Docker hub에 Push

주의해야 할 점은, docker image의 tag에 docker hub 사용자 이름을 넣어야 한다는 점이다.

환경 변수 같은 경우에는 해당 Repository의 Settings Security에 들어가면 추가할 수 있다. 

Github Actions 설정이 모두 끝났다면 코드를 master branch에 push 해보자.

그러면 위와 같이 Actions이 수행되는 것을 볼 수 있다. 만약 Complete job을 확인할 수 있다면 Docker hub에 정상적으로 이미지가 올라간 것이다. 눈으로 확인해 보자.

정상적으로 이미지가 올라갔다.

docker pull ds4uoj/test-app
docker run -p 8080:8080 ds4ouj/test-app

로컬에서 이미지를 받아 직접 테스트를 해보자.

정상적으로 컨테이너가 올라갔고, 요청도 잘 보내진다. 즉, 테스트 코드를 전부 통과한 신뢰할 수 있는 Image가 Docker Hub에 존재하는 것이다. 이렇게 CI를 구축했다.

Continuous Deployment를 어떻게 구축할까?

신뢰할 수 있는 코드를 docker image로 만드는 것은 어렵지 않았다. 하지만 이 image를 어떻게 지속적으로 EC2에 올려놓을 수 있을까? 고민이 되었다.

1. Jenkins를 배울까?
Jenkins를 공부해 볼까 생각해 봤다. 한 번도 사용해 본 적은 없지만 가장 큰 문제는 별도의 서버를 둬야 한다는 것이다. 서버를 둔다는 것은 결국 비용적인 문제까지 이어지게 되었다.

2. k8s로 Argo CD와 같은 기술을 사용해 볼까?
k8s를 공부하는 중이기도 하지만, 작은 수준의 클러스터를 관리하기 위해 k8s를 적용하는 비용이 낭비라고 생각했다.

3. AWS Codedeploy를 사용할까?
이전에 사용해 본 적은 있지만 유료 서비스이기 때문에 매력적이지 못했다.

그래서 Docker Swarm 자체에서 제공하는 기능만으로 Docker Hub에 image가 올라가면 trigger가 되어 rolling update를 하는 방법은 없을까 고민했다. 자료를 찾다 보니 Swarmpit이라는 도구를 통해 아주 간단하게, 심지어 무료로 CD를 구축할 수 있다는 사실을 알게 되었고 Swarmpit을 사용하기로 결정했다.

Swarmpit 사용하기

docker run -it --rm \
  --name swarmpit-installer \
  --volume /var/run/docker.sock:/var/run/docker.sock \
swarmpit/install:1.9

우선 Swarmpit 공식 홈페이지에 들어가 Swarmpit 다운로드 스크립트를 받았다.

설치를 하다 보면 위와 같은 입력을 받게 되는데, admin과 password는 swarmpit으로 접속할 때 필요한 username password를 지정하는 것이기에 꼭 기억하도록 하자.

설치가 완료되면 ip주소:888로 접속해 보자.

그러면 위와 같은 화면을 볼 수 있다. 앞서 등록한 Username과 Password를 입력하고 접속해 보자.

로그인에 성공했다면 Services 탭에 들어가 New Service를 만들어주자.

들어가서 사용할 Repository를 입력해 주자. 앞서 Github Actions로 생성한 ds4ouj/test-app이라는 repository를 사용하기로 했다.

현재 노드의 개수가 3개이므로, Replica의 개수를 3으로 지정했다.

나머지 설정은 건너뛰고, Resources를 할당해 주자. 나는 넉넉하게 6MB를 할당했다.

그리고 아주 중요한 DEPLOYMENT 탭이다. 여기서 autodeploy를 켜주도록 하고, Deploy 버튼을 눌러 서비스를 생성하자.

 

GitHub - swarmpit/swarmpit: Lightweight mobile-friendly Docker Swarm management UI

Lightweight mobile-friendly Docker Swarm management UI - GitHub - swarmpit/swarmpit: Lightweight mobile-friendly Docker Swarm management UI

github.com

swarmpit 공식문서에 따르면, 이 옵션은 새 버전의 Service image가 push 되었는지 확인하고 서비스를 자동으로 업데이트하는 자동 재배포 기능을 제공한다고 한다. 그리고 모든 노드를 동시에 업데이트하는 것이 아니고, 순차적으로 업데이트하기 때문에 무중단 배포까지 자동으로 수행할 수 있다.

잠시 기다리면, mywas라는 이름의 서비스가 정상적으로 생성된 것을 볼 수 있다.

docker service ps [ps id]

위의 명령어를 통해 상세한 service 정보를 살펴보면 아래와 같다.

현재 테스트를 위해 여러 번 서비스를 생성했지만, mywas.1 mywas.2 mywas.3가 정상적으로 동작중인 것을 볼 수 있다.

Continuous Deployment Test

Docker image를 노드에서 동작시키는 것은 성공했지만, CD가 적용된 것은 아직 모른다. 직접 테스트를 해보자.

package docker.swarm.test.controller;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;

@RestController
public class MainController {


  @GetMapping("/hello")
  public String getRequest() {
    System.out.println("Hello");
    System.out.println("V2 Deploy");
    return "Hello world!";
  }
}

가장 간단한 방법은 코드에 출력문을 넣고, 이 출력문을 눈으로 볼 수 있는지 확인하면 될 것이다. 그래서 위와 같이 controller 코드를 업데이트하고 Push 했다.

Swarmpit Services 탭에서도 업데이트가 정상적으로 된 것을 확인했다. 이제 요청을 보내보자.

Node에서 V2 Deploy라는 출력문이 정상적으로 확인된다. 즉, 코드를 푸시하기만 했는데 운영 중인 서비스에 코드가 자동으로 업데이트된 것이다.

이 코드는 test 코드를 통과한 코드이고, 자동으로 서비스 환경에 배포가 된 CI/CD 파이프라인을 구축한 것이다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함