이전 CI에 이어 CD를 만들어보겠습니다.
github actions의 yaml 파일 관련 문법은 이전 글에서 언급했으므로 생략하겠습니다.
CD를 구축하기 위해서 github actions에서 제공하는 self-hosted runners를 사용했습니다.
현재 진행하고 있는 프로젝트의 EC2는 우아한테크코스 ip로만 접속 가능하기 때문에 github actions에서 제공하는 가상 머신이 scp를 통해 빌드 파일을 전송하는 것이 불가능했습니다.
팀 동료가 self-hosted runners는 EC2 내부에서 외부로 접근하는 방식이어서 CD가 가능하다고 말해주어서 해당 방법으로 CD를 구축하게 되었습니다.
공식 문서에 따르면 작업을 실행하기 위해 배포하고 관리하는 시스템이라고 합니다.
github-hosted runners는 깃허브의 가상 머신을 사용하여 빌드했다면 self-hosted runners는 사용자의 서버에서 직접 빌드하는 방식입니다.
self-hosted runners는 프로젝트의 서버 자원을 사용하기 때문에 잡일은 최대한 github-hosted runners에게 시키고 싶었습니다.
self-hosted runners에서는 오직 빌드된 jar 파일만 실행시키는 것을 원했는데요. 외부에서 ec2에 scp가 불가능하기에 도커를 이용했습니다.
github-hosted runners에서 jar 파일을 빌드하고 docker hub에 private image를 push하도록 구성했습니다.
ec2에서는 업데이트된 image를 docker hub로부터 pull 받고 해당 image를 이용하는 container를 실행시킵니다.
상세한 순서는 아래와 같습니다.
application-dev.yml
파일로 환경 설정한다.단계 하나하나 알아보도록 하겠습니다. ( 이전 포스트에 올린 github-hosted runners의 1~4 단계는 생략하겠습니다.)
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2.9.1
도커 action을 실행하기 위한 세팅입니다.
- name: Login to Docker Hub
uses: docker/login-action@v2.2.0
with:
username: ${{ secrets.DOCKERHUB_DEPLOY_USERNAME }}
password: ${{ secrets.DOCKERHUB_DEPLOY_TOKEN }}
docker 계정의 이메일과 토큰을 github에 secrets로 등록합니다.
그래야 github-hosted runners가 등록한 이메일과 토큰으로 로그인할 수 있습니다. (토큰 대신 password를 입력해도 괜찮습니다. 하지만 토큰을 권유한다는 메시지가 뜨더라구요!)
docker에서 토큰을 발급받는 절차입니다.
우선 docker hub에 접속하여 settings -> security로 이동합니다.
New Access Token 버튼을 클릭하여 새로운 토큰을 발급받습니다.
토큰을 복사하여 secrets에 저장합니다.
- name: Docker Image Build
run: |
docker build --platform linux/x64/v8 -t shb03323/cicd -f Dockerfile .
docker 레포지토리에 image를 빌드하는 명령어입니다.
이미지를 만들기 위해서는 docker hub의 레포지토리가 필요한데요. 한번 만들어보겠습니다.
먼저 docker hub의 repositorys 메뉴에 들어갑니다.
그 후에 private repository를 생성합니다. 무료 계정이면 하나의 private repository를 만들 수 있습니다.
위의 스크립트에 -f Dockerfile .
명령어가 있는데요. 이는 프로젝트 내부의 Dockerfile이라는 것을 이용하여 빌드한다는 뜻입니다.
이 Dockerfile을 이용해서 jar 파일을 만들어보겠습니다.
프로젝트 레포지토리 최상단에 Dockerfile을 만들어 아래와 같은 내용으로 구성했습니다.
FROM arm64v8/amazoncorretto:17
WORKDIR /app
COPY ./build/libs/cicd-0.0.1-SNAPSHOT.jar /app/cicd.jar
CMD ["java", "-jar", "-Dspring.profiles.active=dev", "cicd.jar"]
jdk 17로 설정하고, docker 레포지토리에 cicd.jar를 복사합니다.
그 후에 jar 파일로 빌드합니다.
- name: Docker Hub Push
run: docker push shb03323/cicd
도커 image push 명령어를 실행합니다.
EC2에 self-hosted runners를 등록해야 image를 pull 받을 수 있습니다.
한번 등록해보도록 하겠습니다.
레포지토리의 settings -> Actions -> Runners 탭을 클릭하면 위와 같은 화면이 나옵니다.
New self-hosted runner 버튼을 클릭하면 명령어들이 나오는데, 그대로 EC2 서버에 입력하시면 됩니다!
완료하면 예쁜 CLI창이 나옵니다.
Runners를 다시 확인했을때 self-hosted runner가 생성된 것을 볼 수 있습니다.
github-hosted runners와 다른 환경에서 실행되기 때문에 작업 또한 달라야합니다.
따라서 cd라는 이름을 가진 job를 생성했습니다.
cd:
needs: ci
runs-on: [ self-hosted, Linux, x64 ]
ci job를 실행한 후에 cd 작업이 수행될 수 있도록 needs
속성을 넣어주었습니다.
또한, 환경도 다르게 설정해주었는데요. 이는 EC2 t2.micro의 환경입니다.
- name: Pull Latest Docker Image
run: |
sudo docker login --username ${{ secrets.DOCKERHUB_DEPLOY_USERNAME }} --password ${{ secrets.DOCKERHUB_DEPLOY_TOKEN }}
if sudo docker inspect cicd-container &>/dev/null; then
sudo docker stop cicd-container
sudo docker rm -f cicd-container
sudo docker image prune -af
fi
sudo docker pull shb03323/cicd:latest
이전에 docker hub에 push한 image를 받기 위해서는 로그인이 필요합니다.
docker hub에 로그인 유지 시간이 있을 것이 분명하기 때문에 일단 계속 로그인 시도하도록 설정했습니다.
그리고 실행중인 container를 삭제하고 새로운 이미지로 pull 받았습니다.
- name: Run Container
run: |
sudo docker run --name cicd-container -p 8080:8080 shb03323/cicd:latest 1>> build.log 2>> error.log &
최신 상태로 pull 받은 image를 이용하여 container를 실행하는 명령어입니다.
이로써 모든 단계가 완료되었습니다.
name: continuous-deploy
on:
push:
branches:
- main
jobs:
ci:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Make application-dev.yml
if: ${{ github.event.push.head.ref == 'main' }}
env:
PROPERTIES_DEV: ${{ secrets.PROPERTIES_DEV }}
run: |
cd ./src/main/resources
touch ./application-dev.yml
echo "${PROPERTIES_DEV}" > ./application-dev.yml
shell: bash
- name: Build with Gradle
uses: gradle/gradle-build-action@v2.6.0
with:
arguments: build
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2.9.1
- name: Login to Docker Hub
uses: docker/login-action@v2.2.0
with:
username: ${{ secrets.DOCKERHUB_DEPLOY_USERNAME }}
password: ${{ secrets.DOCKERHUB_DEPLOY_TOKEN }}
- name: Docker Image Build
run: |
docker build --platform linux/x64/v8 -t shb03323/cicd -f Dockerfile .
- name: Docker Hub Push
run: docker push shb03323/cicd
cd:
needs: ci
runs-on: [ self-hosted, Linux, X64 ]
steps:
- name: Pull Latest Docker Image
run: |
sudo docker login --username ${{ secrets.DOCKERHUB_DEPLOY_USERNAME }} --password ${{ secrets.DOCKERHUB_DEPLOY_TOKEN }}
if sudo docker inspect cicd-container &>/dev/null; then
sudo docker stop cicd-container
sudo docker rm -f cicd-container
sudo docker image prune -af
fi
sudo docker pull shb03323/cicd:latest
- name: Run Container
run: |
sudo docker run --name cicd-container -p 8080:8080 shb03323/cicd:latest 1>> build.log 2>> error.log &
한 번 확인해볼까요?
main에 push를 하니 github actions가 동작했습니다.
CI/CD 둘 다 성공한 것을 볼 수 있습니다.
EC2에서 docker가 실행된 것을 볼 수 있습니다. 비록 에러나서 꺼졌지만, cicd는 성공적으로 완수했습니다.
아직 actions로 밖에 CI/CD를 구축해보지 않았지만 과금이 되면 젠킨스로 넘어가지 않을까 합니다.
github actions는 한 달 2000분까지만 무료라고 하더군요...