멍두의 개발새발
[개발 후 운영] 1-2. springBoot CICD (feat EC2, Git Action, Docker) 본문
[개발 후 운영] 1-2. springBoot CICD (feat EC2, Git Action, Docker)
멍두 2024. 10. 1. 22:51WHY
서비스를 운영하기 시작하면서 CICD가 절실해졌다
매번 직접 build하고 upload하고 기존 실행하던 process 종료하고 다시 실행시키고 제대로 실행됐는지 확인하고 오류나면 다시 코드짜고 다시 업로드하고 너무 생산성이 떨어진다고 판단하여 github action을 이용해 자동 배포를 해보기로 했다
💡 Goal 💡 : 개발 서버를 github action을 이용하여 자동배포 환경을 갖추어 불필요한 반복적인 행동을 줄이자
WHAT
1. 코드를 git의 develop branch에 push, pull request
2. GitAction : bootjar build ▷ docker image build ▷ docker hub에 image push
3. EC2 : docker hub에서 image pull ▷ run docker container
Deploy Flow
HOW
EC2 배포 ▷ EC2 서버에 docker 설치 ▷ Gitflow 작성 ▷ 배포 완
사전에 필요한 것
ec2 배포, docker file 작성, docker hub 회원가입, docker repository 만들어 놓기, docker token 발급
1. EC2 배포
EC2는 ubuntu로 배포
인바운드 규칙에서 githubaction이 ec2에 접근하기 위해서는 일단 ssh 모든 요청을 열어놔야한다.
이 부분은 추후에 동적으로 github action ip를 허용했다가 다시 닫는 방법으로 변경할 예정
또한 tomcat은 8080포트를 사용하고 나는 http로 접근할 것 이기 때문에 80 요청을 8080으로 redirect해주는 서버 설정도 해주었다.
2. docker 설치 & 환경변수 설정
ubuntu에 접속한다
나는 intelliJ에 ssh로 연결하여 실행했다. (참고 글)
도커 설치 코드
# 패키지 업데이트
sudo apt update
#https 관련 패키지 설치
sudo apt install apt-transport-https ca-certificates curl software-properties-common
# docker repository 접근을 위한 gpg 키 설정
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# docker repository 등록
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
# 다시 업데이트
sudo apt update
# 도커 설치
sudo apt install docker-ce
#설치 확인
docker --version
# sudo 없이 docker 명령어 사용하기
# 현재 사용자를 docker group에 포함
sudo usermod -a -G docker ubuntu
# docker 데몬 소켓 파일 권한 변경
sudo chmod 666 /var/run/docker.sock
# 터미널 재시작 후 결과 확인
id -nG
환경변수 설정
이 부분에서 좀 애를 먹었었다.
기존 방식 : docker를 사용하지 않고, 리눅스 서버에 필요한걸 전부 설치 + 환경변수 서버에 저장
변경 방식 : docker 사용, 환경변수를 docker container에 입력하고 실행해야함
docker container에 환경변수를 넣는 다양한 방법이 있었으나 나는 github secrect + .env파일 등록으로 결정했다.
최대한 간단한 방식으로 하려고(아직 도커 초보) docker run 할 때 -e 환경변수 = 환경변수내용 으로 넣으려 했으나 -e만 넣으면 command error가 발생해서 그다음으로 간단한 방식인 .env로 변경했다.
.env파일을 docker image 빌드할 곳에 같이 만든다 (다른 곳에 만들어도 되지만 그러면 cd로 파일 위치를 다시 변경해주어야해서 그냥 안전하게 같은 디렉토리 안에 만들었다)
환경변수=환경변수내용
으로 만들고 저장하면 끝!
3. Gitflow 작성
스크립트
# 워크플로우 이름 설정
name: Java CI with Gradle
# 워크플로우 트리거 설정
on:
push:
branches: [ "test" ] # test 브랜치에 푸시될 때 실행
pull_request:
branches: [ "test" ] # test 브랜치로의 PR이 생성될 때 실행
# github action vm의 권한 read로 설정
permissions:
contents: read
# 작업 정의
jobs:
# Docker 이미지 빌드 및 푸시 작업
build-docker-image:
runs-on: ubuntu-latest # 최신 Ubuntu 러너에서 실행
steps:
# 1. 코드 체크아웃
- uses: actions/checkout@v3
# 2. JDK 21 설정
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
# 3. Gradle을 사용하여 프로젝트 빌드
- name: Build with Gradle
run: |
chmod +x ./gradlew
./gradlew clean build -x test
# 4. Docker 이미지 빌드
- name: Build Docker image
run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:latest .
# 5. Docker Hub 로그인
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
# 6. Docker 이미지를 Docker Hub에 푸시
- name: Push Docker image
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:latest
# EC2에서 Docker 이미지 실행 작업
deploy-to-ec2:
needs: build-docker-image # build-docker-image 작업이 완료된 후 실행
runs-on: ubuntu-latest
steps:
- name: Deploy to EC2
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.WAS_HOST }} #서버의 public 주소
username: ${{ secrets.WAS_USERNAME }} #접속할 사용자
key: ${{ secrets.WAS_KEY }} #SSH 키
port: ${{ secrets.WAS_SSH_PORT }}
script: |
cat ~/my_password.txt | docker login --username ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
if [ "$(docker ps -qa)" ]; then
docker rm -f $(docker ps -qa)
else
echo "No containers to remove."
fi
docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}
docker run -d -p 8080:8080 --env-file /home/ubuntu/src/config/development.env --name app ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}
위에 workflow 그림대로 동작하는 코드이다
예민한 정보들은 반드시 github secrect에 등록해놓고 사용하면 된다.
그리고 github action에서 ec2와 연결하는 방법은 appleboy를 이용해서 ssh로 연결했다.
처음에는 self host로 연결했는데 githubaction이 연결을 못하고 계속 대기만 하는 오류가 있어서 appleboy방식으로 변경했다.
이때 key는 ec2 인스턴스를 생성할 때 발급받은 .pem 코드를 txt파일로 변경한 것을 복사 붙여넣기 하면 된다.
ec2 script 설명
1. docker login
2. docker 실행 중인 container 종료, 만약 실행 중인게 없다면 No containers to remove. 출력
3. repo의 가장 최신 image pull
4. 환경변수 설정하고 docker run
4. 배포 완
성공 😀
진짜 많이 실패했지만 그래도 성공했다!!!
느낀점
배포를 할 때마다 느끼는 점이지만 남들의 글을 참고해서 진행하지만 사소한 환경들이 다 달라서 오류가 많이 나고, 찾기도 힘든 것 같다.
그럴 때 마다 생성형 AI에 의존하고 싶어지는데, 오히려 이런 부분은 조금 시간이 걸리더라도 내가 직접 인터넷, 공식문서를 읽고 해결하는게 더 빠른 방법인 것 같다.
내가 짠 스크립트를 ai에 맡기고, 그 코드가 다시 오류가 난다면 결국 또 ai에 의존할 수 밖에 없는 그런 딜레마에 빠지다가 결국 ai는 똑같은 말 계속하고.. 이러다 0 으로 돌아간 경험이 많아서..ㅠ
내 글이 딱히 가독성이나 정보가 뛰어난 글은 아니지만 그래도 매애애애우 간단하게 배포한 편이라 이 방법을 기반으로 다양하게 다른 방식으로 뻗어나갈 수 있을 것 같다.
다들 화이팅!!
NEXT
보안 측면에서 개선해야할 부분이 매우 많다
- github action host ssh 연결 수락했다가 다시 끊기
- docker 로그인 방법 변경
- env 파일 암호화
- 리눅스 파일 접근 제한
이후 운영 서버도 이런 식으로 배포 예정
- 운영 서버도 cd로 배포하는데 ngnix로 무중단 배포하기
- CICD를 위해 테스트 코드 작성
'Programming > Project' 카테고리의 다른 글
[개발 후 운영] 1-1. 운영 데이터베이스와 테스트 데이터베이스의 분리 (3) | 2024.09.19 |
---|---|
[IntelliJ] git으로 restore, reset 등등으로 파일이 다 날라갔을 때 (4) | 2024.07.31 |