사이드 프로젝트에서 Github Actions 와 CodeDeploy를 이용하여 자동 배포 환경을 제작했습니다. 하지만 nginx, certbot, redis 같이 의존성이 있는 파일을 설치 및 환경 설정을 하면서 서버에 부하가 크고 설정의 귀찮음이 있었습니다.
그래서 사이드 프로젝트에서 Docker-hub와 nginx, certbot(SSL/https)을 도커 이미지를 통해 인증서를 발급하고 배포 자동화(CI/CD)하기로 수정했습니다.😊
➡️ 본 과정은 윈도우10 OS에서 진행되었습니다.
FROM openjdk:11
ARG JAR_FILE=build/libs/{빌드한 jar 파일명}
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
스프링 프로젝트 파일에 도커 파일을 작성합니다. 도커 파일은 이미지를 빌드하여, 빌드한 이미지를 기반으로 컨테이너가 실행됩니다.
[설명]
base 이미지를 openjdk:11로 설정 및 JAR_FILE 변수 파일경로를 등록한다.
빌드 파일을 컨테이너의 app.jar로 옮기고 컨테이너에서 java -jar /app.jar을 실행한다.
- Github Actions를 이용하여, 프로젝트 파일을 master 브랜치에 push 할 때마다(수정), 빌드 파일을 새로 만들 것입니다!
우선 EC2 인스턴스에, docker-compose를 설치해야 합니다.
Docker-compose 설치 방법
version: '3'
services:
web:
container_name: web
image: {Docker 닉네임}/{생성 image}
expose:
- 8080
ports:
- 8080:8080
nginx:
container_name: nginx
image: nginx:latest
restart: always
volumes:
- ./conf/:/etc/nginx/conf.d
- /data/certbot/conf:/etc/letsencrypt
- /data/certbot/www:/var/www/certbot
ports:
- 80:80
- 443:443
depends_on:
- web
web의 image: {Docker 닉네임}/{생성 image}는 자신의 Docker 닉네임과, 생성할 image 이름으로 변경해주세요.
EX) abc123/web
[설명]
컨테이너는 web, nginx을 생성합니다.
web은 나의 docker-hub에 올리고, nginx는 docker에 이미 존재하는 nginx를 이용합니다.
EC2 인스턴스에 docker-compose.yaml을 생성합니다.
docker run -it --rm --name certbot \
-v '/data/certbot/conf:/etc/letsencrypt' \
-v '/data/certbot/www:/var/www/certbot' \
certbot/certbot certonly -d 'mydomain.or.kr' --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory
EC2 인스턴스에 위 명령어를 입력해주세요!
mydomain.or.kr을 내 도메인으로 변경해주세요.
[설명]
-v 명령어는 바인드 볼륨을 정해주는 명령어입니다.
(서버의 파일 경로 : 컨테이너의 파일 경로)
자신의 DNS 서버에 TXT 레코드를 추가해야 됩니다.
dns명은 _acme-challenge.mydomain.com이고 txt는 the following value(Ma...cM)가 된다. txt 레코드를 추가하고 잠시 2~3분 정도는 기다렸다가 엔터를 눌러주자.
위 화면은 인증서 발급이 성공한 것입니다.
인증서는 도커 내 컨테이너인 /etc/letsencrypt/live/{도메인 명}/ 디렉토리에 저장됩니다. 바인드 마운트 되었으므로, 서버 내에는 data/certbot 디렉토리 내에 존재합니다.
server {
listen 80;
server_name {도메인 명};
return 301 https://{도메인 명}$request_uri; # http로 들어오면 https로 redirect 해주는 부분
}
server {
listen 443 ssl;
server_name {도메인 명};
# Certificate
ssl_certificate /etc/letsencrypt/live/{도메인 명}/fullchain.pem;
# Private Key
ssl_certificate_key /etc/letsencrypt/live/{도메인 명}/privkey.pem;
location / {
proxy_pass http://{퍼블릭 ip 주소}:8080; # 자신의 springboot app이사용하는 포트
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
{도메인 명}은 자신이 쓰는 도메인으로 변경하고, {퍼블릭 ip 주소}는 EC2 인스턴스의 퍼블릭 ip 주소로 변경해서 넣어주세요.
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
# Repo Action 페이지에 나타날 이름
name: Spring Boot & Gradle CI/CD
# Event Trigger
# master branch에 push 또는 pull request가 발생할 경우 동작
# branch 단위 외에도, tag나 cron 식 등을 사용할 수 있음
on:
push:
branches: [ master ]
jobs:
build:
# 실행 환경 지정
runs-on: ubuntu-18.04
# Task의 sequence를 명시한다.
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
## create application.yaml
- name: make application.yml
run: |
## create application.yml
cd ./src/main/resources
# application.yml 파일 생성
touch ./application.yml
# GitHub-Actions 에서 설정한 값을 application.yaml 파일에 쓰기
echo "${{ secrets.DATABASE }}" >> ./application.yml
shell: bash
- name: Grant execute permission for gradlew
run: chmod +x gradlew
# Build
- name: Build with Gradle
run: ./gradlew clean build
## 웹 이미지 빌드 및 도커허브에 push
- name: web docker build and push
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -t ${{ secrets.DOCKER_REPO }}/bangu-web .
docker push ${{ secrets.DOCKER_REPO }}/bangu-web
## docker compose up
- name: executing remote ssh commands using password
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST_ID }}
username: ec2-user
key: ${{ secrets.PRIVATE_KEY }}
script: |
sudo docker rm -f $(docker ps -qa)
sudo docker pull ${{ secrets.DOCKER_REPO }}/bangu-web
docker-compose up -d
docker image prune -f
[설명]
on:
push:
branches: [ master ]
✔️ master 브랜치에 push 될 때마다 배포하는 것으로 설정합니다.
checkout & setup
jobs:
build:
# 실행 환경 지정
runs-on: ubuntu-18.04
# Task의 sequence를 명시한다.
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
runs-on은 github action의 CI서버 runner가 어떤 환경을 갖출지 고르는 것 입니다. (ubuntu-18.04)
checkout: github action과 연결된 레포지토리의 코드를 runner로 옮기는 것
set up: JDK 11 버전 으로 작성된 프로젝트이기 때문에 JDK 11 로 설정(JDK는 프로젝트마다 변경해주세요.)
## create application.yaml
- name: make application.yml
run: |
## create application.yml
cd ./src/main/resources
# application.yml 파일 생성
touch ./application.yml
# GitHub-Actions 에서 설정한 값을 application.yaml 파일에 쓰기
echo "${{ secrets.DATABASE }}" >> ./application.yml
shell: bash
## gradle build
- name: Build with Gradle
run: ./gradlew bootJar
## 웹 이미지 빌드 및 도커허브에 push
- name: web docker build and push
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -t ${{ secrets.DOCKER_REPO }}/bangu-web .
docker push ${{ secrets.DOCKER_REPO }}/bangu-web
✔️ 새로 빌드한 파일을 넣은 이미지를 빌드합니다. 그 이미지를 docker hub에 push해서 EC2서버에서 가져다가 쓸 수 있게 합니다.
✔️ 레포이름/{프로젝트 명} 이미지가 작성해둔 dockerfile을 기반으로 생성됩니다.
## docker compose up
- name: executing remote ssh commands using password
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST_ID }}
username: ec2-user
key: ${{ secrets.PRIVATE_KEY }}
script: |
sudo docker rm -f $(docker ps -qa)
sudo docker pull ${{ secrets.DOCKER_REPO }}/bangu-web
docker-compose up -d
docker image prune -f
✔️ appleboy/ssh-action@master를 통해서 ssh접속이 가능합니다.
접속시 필요한 정보는 모두 secret에 등록합니다.
필요 없는 컨테이너들을 지워주고, web 이미지를 docker hub에서 pull받고 docker-compose up -d(background 실행)로 실행 하게 됩니다.
✔️ master 브랜치에 push하면 Github Actions의 절차대로 CI/CD가 진행됩니다.
시크릿은 repository settings에 Secrets>Actions에 등록해주면 됩니다.
✔️ 터미널에서 작업을 자동화 할수 있습니다.
$ ssh-keygen -t rsa -b 4096 -C "[내메일]" -f spring-cicd
✔️ CMD 창에서 위 방식을 통해 spring-cicd, spring-cicd.pub 파일을 만들어 줍니다.
공개키(spring-cicd)의 내용은 EC2 서버의 ~/.ssh 경로의 authorized_keys 에다가 붙여 넣어주세요.
spring-cicd 파일에 담긴 개인키의 내용(!!모두 복사해야 합니다.) GITHUB SECRET의 PRIVATE_KEY로 등록합니다.