티스토리 뷰
이제 본격적으로 Github Action 사용한다.
그 전에 docker compose 파일을 만들어야 하기에, 만약 컨테이너 안에 접속되어 있다면 exit를 이용해 ubuntu 서버로 나가자.
vim docker-compose-blue.yml
yml 파일은 다음과 같이 작성한다.
version: '3.8'
services:
blue:
image: docker 레포지토리 사용자 이름/live_server:latest
container_name: blue
ports:
- "8080:8080"
environment:
- PROFILES=blue
- ENV=blue
그리고 green을 위해서 하나 더 만든다.
cp로 copy한다.
cp docker-compose-blue.yml ./docker-compose-green.yml
vim docker-compose-green.yml
green은 8081로 설정했으므로 8081로 설정한다.
version: '3.8'
services:
green:
image: docker 레포지토리 사용자 이름/live_server:latest
container_name: green
ports:
- "8081:8081"
environment:
- PROFILES=green
- ENV=green
이제 github로 간다.
github Actions 설정하기
github의 Actions에 들어가서, workflow yourself로 들어가서 설정한다.
해당 yaml 파일을 만들 때 이렇게 한다.
name: CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest #우분투로 가상을 쓴다.
steps:
- uses: actions/checkout@v3 #uses는 깃허브 액션의 템플릿. 이미 만들어진 체크아웃
- name: Install JDK 11
uses: actions/setup-java@v3 #마찬가지
with:
java-version: '11'
distribution: 'temurin'
- name: Build with Maven #단위는 네임 별로 끊어서 간다.
run: |
chmod 777 ./mvnw #프로젝트를 빌드하기 위해서 권한을 모두 준다.
./mvnw clean package -Dtestskip
- name: Login to DockerHub #dockerhub에 로그인
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Docker
run: docker build --platform linux/amd64 -t ${{ secrets.DOCKERHUB_USERNAME }}/live_server . #이미지 만드는 과정
- name: Push Docker
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/live_server:latest #dokcerhub에 올린다.
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Set target IP
run: |
STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.LIVE_SERVER_IP }}/env")
echo $STATUS
if [ $STATUS = 200 ]; then
CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.LIVE_SERVER_IP }}/env")
else
CURRENT_UPSTREAM=green
fi
echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
if [ $CURRENT_UPSTREAM = blue ]; then
echo "CURRENT_PORT=8080" >> $GITHUB_ENV
echo "STOPPED_PORT=8081" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
elif [ $CURRENT_UPSTREAM = green ]; then
echo "CURRENT_PORT=8081" >> $GITHUB_ENV
echo "STOPPED_PORT=8080" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV
else
echo "error"
exit 1
fi
- name: Docker compose
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/live_server:latest
sudo docker-compose -f docker-compose-${{env.TARGET_UPSTREAM}}.yml up -d
- name: Check deploy server URL
uses: jtalk/url-health-check-action@v3
with:
url: http://${{ secrets.LIVE_SERVER_IP }}:${{env.STOPPED_PORT}}/env
max-attempts: 3
retry-delay: 10s
- name: Change nginx upstream
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker exec -i nginxserver bash -c 'echo "set \$service_url ${{ env.TARGET_UPSTREAM }};" > /etc/nginx/conf.d/service-env.inc && nginx -s reload'
- name: Stop current server
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker stop ${{env.CURRENT_UPSTREAM}}
sudo docker rm ${{env.CURRENT_UPSTREAM}}
먼저 빌드 과정을 거치고, build가 되면 정상적으로 실행을 한다.
gradle 버전은 이렇게 바뀐다.
name: CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Gradle
run: |
chmod +x ./gradlew
./gradlew clean build
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Docker
run: docker build --platform linux/amd64 -t ${{ secrets.DOCKERHUB_USERNAME }}/spring-boot-developer .
- name: Push Docker
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/spring-boot-developer:latest
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Set target IP
run: |
STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.LIVE_SERVER_IP }}/env")
echo $STATUS
if [ $STATUS = 200 ]; then
CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.LIVE_SERVER_IP }}/env")
else
CURRENT_UPSTREAM=green
fi
echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
if [ $CURRENT_UPSTREAM = blue ]; then
echo "CURRENT_PORT=8080" >> $GITHUB_ENV
echo "STOPPED_PORT=8081" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
elif [ $CURRENT_UPSTREAM = green ]; then
echo "CURRENT_PORT=8081" >> $GITHUB_ENV
echo "STOPPED_PORT=8080" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV
else
echo "error"
exit 1
fi
- name: Docker compose
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/spring-boot-developer:latest
sudo docker-compose -f docker-compose-${{env.TARGET_UPSTREAM}}.yml up -d
- name: Check deploy server URL
uses: jtalk/url-health-check-action@v3
with:
url: http://${{ secrets.LIVE_SERVER_IP }}:${{env.STOPPED_PORT}}/env
max-attempts: 3
retry-delay: 10s
- name: Change nginx upstream
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker exec -i nginxserver bash -c 'echo "set \$service_url ${{ env.TARGET_UPSTREAM }};" > /etc/nginx/conf.d/service-env.inc && nginx -s reload'
- name: Stop current server
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker stop ${{env.CURRENT_UPSTREAM}}
sudo docker rm ${{env.CURRENT_UPSTREAM}}
Dockerfile도 만들어준다.
FROM openjdk:17-jdk-slim
ARG JAR_FILE=build/libs/*.jar
ARG PROFILES
ARG ENV
ENTRYPOINT ["java", "-Dspring.profiles.active=${PROFILES}", "-Dserver.env=${ENV}", "-jar", "app.jar"]
여기서 spring.profiles.active는 앞서 설정해줬던 yml 파일에 있는 값들이 들어간다.
Docker secret 설정
Github Action에서 secret 설정을 좀 해줘야 한다.
Docker에 접속하기 위해서이다.
settings - settings and variables- actions에 들어가서 new repository secret을 만든다.
이름은 다음과 같이 입력
DOCKERHUB_USERNAME
secret에는 유저 이름을 써준다.
그렇게 하나 추가
그리고 DOCKERHUB_TOKEN이라고 하나 더 만든다.
저장해놨던 token을 secret에 추가해서 만든다.
EC2_SSH_KEY도 추가해준다.
.pem에 있는 파일을 추가해주는 것이다.
LIVE_SERVER_IP도 secret으로 추가해준다.
secret에다 담아둬서 github에서의 yml을 실행할 때 볼 수 없게 만든다.
이러면 이제 build까지는 잘 실행되는 걸 볼 수 있다.
배포 (Deploy)
이제 배포에 대한 설명으로 넘어가자.
EC2 환경에서 pull을 받고 실행을 시켜야 한다.
현재 blue 서버가 실행이 있다고 해보자. 그러면 현재 blue인지 green인지 일단 체크를 한다.
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Set target IP
run: |
STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.LIVE_SERVER_IP }}/env")
echo $STATUS
if [ $STATUS = 200 ]; then
CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.LIVE_SERVER_IP }}/env")
else
CURRENT_UPSTREAM=green
fi
echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
if [ $CURRENT_UPSTREAM = blue ]; then
echo "CURRENT_PORT=8080" >> $GITHUB_ENV
echo "STOPPED_PORT=8081" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
elif [ $CURRENT_UPSTREAM = green ]; then
echo "CURRENT_PORT=8081" >> $GITHUB_ENV
echo "STOPPED_PORT=8080" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV
else
echo "error"
exit 1
fi
curl은 요청을 날리는 건데, http:// secret.LIVE_SERVER_IP /env 요청에 대한 응답을 반환한다.
http 코드를 가지고 와서 설정하겠다 이런 것이다.
echo로 status 변수에 있는 코드를 받아서 출력해준다.
만약에 status code가 200이라면, 해당 서버에 env라는 요청이 날라간다.
처음에 요청 할 때는 404여서 green으로 연결된다.
green이라는 값을 Github env에 넣어준다.
그렇게 blue냐 green이냐에 따라 포트를 8080 또는 8081로 포트를 켜준다.
- name: Docker compose
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/spring-boot-developer:latest
sudo docker-compose -f docker-compose-${{env.TARGET_UPSTREAM}}.yml up -d
- name: Check deploy server URL
uses: jtalk/url-health-check-action@v3
with:
url: http://${{ secrets.LIVE_SERVER_IP }}:${{env.STOPPED_PORT}}/env
max-attempts: 3
retry-delay: 10s
- name: Change nginx upstream
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker exec -i nginxserver bash -c 'echo "set \$service_url ${{ env.TARGET_UPSTREAM }};" > /etc/nginx/conf.d/service-env.inc && nginx -s reload'
- name: Stop current server
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker stop ${{env.CURRENT_UPSTREAM}}
sudo docker rm ${{env.CURRENT_UPSTREAM}}
그 다음에는 docker-compose를 실행시킨다.
github action에서 EC2로 접속을 할 건데, 그걸 자동으로 해줄 수 있게끔 username을 설정해준다.
나머지도 compose를 통해 설정해주면 자동 deploy 방식 끝이다.