
CI는 지속적 통합이라는 뜻으로, 새로운 코드 변경 사항이 정기적으로 빌드 및 테스트 되어 공유 레포지토리에 통합하는 것
CD는 지속적인 서비스 제공 혹은 지속적인 배포라는 뜻으로,
Continuous Delivery는 공유 레포지토리로 자동으로 Release 하는 것,
Continuous Deployment는 Production 레벨까지 자동으로 deploy 하는 것,
정리하면 CD는 개발자의 변경 사항이 레포지토리를 넘어, 고객의 프로덕션(Production) 환경까지 릴리즈 되는 것
즉, CI/CD는 소프트웨어의 개발, 테스트와 배포를 모두 통합함으로써 소프트웨어 버그를 쉽게 찾아낼 수 있으며, 더 빠른 배포 주기를 가질 수 있게 만들어 준다.
우선 서버와 DB는 AWS를 사용중이다. 이제 어떤 방법으로 배포할지가 문제.
개발환경
Spring Boot 3.1.2
OpenJdk 17
서버에 접속하여 Docker를 설치한다.
sudo apt-get update
sudo apt-get install docker.io
sudo service docker start
Docker-compose도 설치한다.
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
docerk-compose.yml 파일을 추가한다.
cd ~
sudo vi docker-compose.yml
version: '3'
services: # 컨테이너 서비스들
web: # 웹 컨테이너를 만들 것임
container_name: web # 생성할 컨테이너 이름
image: docker_username/docker_repository
ports: # 호스트OS와 컨테이너의 포트를 바인딩
- "80:8080" # 포트포워딩시켜줌
프로젝트 루트 디렉토리에 추가해준다.
FROM openjdk:17
ARG JAR_FILE=./build/libs/*-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
gradle.yml에서 노출되면 안되는 변수들을 github secrets를 통해 숨겨줄 것이다.
repository의 Settings 탭에서
Secrets and Variables > Actions로 이동
New repository secret 클릭

아래 내용을 모두 추가해준다.
APPLICATION_YML : application.yml 코드DOCKER_PASSWORD : docker 비밀번호DOCKER_REPO : docker에 생성할 repository 이름DOCKER_USERNAME : docker usernameHOST : 서버 주소KEY : 서버 key pair 내용깃허브 레파지토리에 들어가서 Actions 탭으로 가서
Java with Gradle이라는 workflow를 클릭한다.

그러면 gradle.yml을 작성하는 페이지로 이동할 텐데
다음 코드를 추가해준다.
name: CI/CD with Gradle
# 언제 이 파일의 내용이 실행될 것인지 정의
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# 코드의 내용을 이 파일을 실행하여 action을 수행하는 주체(Github Actions에서 사용하는 VM)가 읽을 수 있도록 허용
permissions:
contents: read
# 실제 실행될 내용들을 정의
jobs:
build:
runs-on: ubuntu-latest # ubuntu 최신 버전에서 script를 실행
steps:
# 지정한 저장소(현재 REPO)에서 코드를 워크플로우 환경으로 가져오도록 하는 github action
- uses: actions/checkout@v3
# open jdk 17 버전 환경을 세팅
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
# Github secrets로부터 데이터를 받아서, 워크 플로우에 파일을 생성
- name: Make application.yml
run: |
cd ./src/main/resources
touch ./application.yml
echo "${{ secrets.APPLICATION_YML }}" > ./application.yml
shell: bash
# gradle을 통해 소스를 빌드
- name: Build with Gradle
run: |
chmod +x ./gradlew
./gradlew clean build -x test
# dockerfile을 통해 이미지를 빌드하고, 이를 docker repo로 push
- name: Docker build & push to docker repo
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -f Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }} .
docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }}
# appleboy/ssh-action@master 액션을 사용하여 지정한 서버에 ssh로 접속하고, script를 실행
# script의 내용은 도커의 기존 프로세스들을 제거하고, docker repo로부터 방금 위에서 push한 내용을 pull 받아 실행하는 것
# docker-compose를 사용해 백그라운드(-d) 실행
- name: Deploy to server & Run
uses: appleboy/ssh-action@master
id: deploy
with:
host: ${{ secrets.HOST }}
username: ubuntu
key: ${{ secrets.KEY }}
envs: GITHUB_SHA
script: |
sudo docker rm -f $(docker ps -qa)
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }}
docker-compose up -d
docker image prune -f
파일을 커밋해주게 되면 자동으로 actions workflow가 실행된다.

첫 번째 시도에서 이러한 에러가 발생....!
======END======
err: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json?all=1": dial unix /var/run/docker.sock: connect: permission denied
이 문제는 사용자가 /var/run/docker.sock 접근 권한이 없어 발생하는 문제로 사용자가 root:docker 권한을 가지고 있어야 한다.
근데 root 권한을 가지고 실행하는 것은 권장되지 않으므로, 사용자를 docker group에 포함시켜주면 된다.
sudo usermod -a -G docker $USER
다시 실행해보니 성공!!!

참고 자료
코드 Push로 배포까지! Spring Boot + Github Actions + Docker
[Spring Boot] Docker + Github Actions를 활용한 자동 배포
[Docker][해결방법] Got permission denied while trying to connect to the Docker...