개요
슬램덩크 너무 재밌다ㅠㅠ 꼭 보길!!
나는 오히려 상대편 정우성을 보면서, 이 영화를 볼 때 쯤 내 상황이랑 너무 똑같은 것 같아서 심심한 위로를 받았다.
죽어라 노력했는데도 일이 잘 풀리지 않는 경험은 정말 값지다. 값진 이유는 이제부터 내가 증명하면 되겟지 >-<
암튼 그래서 이번 학기에는 저번 방학 때 했던 UMC 프로젝트를 이용해서 내가 써볼 수 있는 모든 백엔드 기술들은 제대로 써볼 생각이다. 생각보다 내가 개발적인 측면과 CS 부분에서 깊이 있게 들어가보진 않은 것 같아서 스스로 배우고 싶은 내용들을 작성해 UMC 팀원들과 스터디를 해보기로 했다!
대충 욕심 내서 아래와 같이 이런 저런 내용들을 일주일에 한 개씩 해보기로 했다. 바쁠텐데 같이 해주는 팀원들에게 너무 고맙다.. 일단 제일 한가한 내가 열심히 임해야겠다.
CI/CD
지속적으로 통합·테스트·배포를 하고 이 흐름을 자동화하는 것을 말한다. 내 전 포스팅을 보면 서버 변경사항이 있을 때마다 ./gradlew clean build -> docker build -> docker push 하는 걸 볼 수 있다. 이 과정은 아주 귀찮고 하찮다..
github actions, jenkins를 이용하면 자동 배포가 가능하다.
우리는 팀원들과 github organization을 사용하여 서버를 만들고 있으므로 GitHub과의 통합이 쉬운 github action와 docker를 연동시켜 배포해보기로 했다.
build pipeline의 장점
위와 같은 CI/CD를 사용하는 이유는 다음과 같다.
1. 명령어 조작을 간단하게 하고 싶다. github actions를 사용하면 git commit이 명령어의 전부이다!
2. 구축 작업을 안전하고 확실하게 하고 싶다. 테스트를 통해 build가 성공될 때에만 배포되도록 진행할 수 있다.
3. 구축 및 테스트 결과와 이력을 축적한 후 팀 단에서 확인하고 싶다. 어떤 주기로 우리가 build했는지, build할 때의 시간은 얼마나 걸렸는지 이력들을 꾸준히 확인해보고 싶다.
구현 결과
구현 과정
ec2 생성
일단 ec2를 생성한다. 나는 프리티어에, ubuntu환경으로 설치하였다.
ec2를 ubuntu환경으로 깔았기 때문에 이후 docker를 리눅스 운영체제 위에서 실행할 수 있는 것이다. 도커에 대한 개념이 잘 안잡혀 있다면 이론 공부를 같이 해두는 게 좋은 것 같다. 가상머신과 컨테이너 등을 키워드로 공부하자!
ec2 생성 과정은 다른 곳에 너무 잘 정리되어 있어서 생략한다.
github action 생성
github action이란 ssh에 접속하여 script명령어를 실행하도록 하는 action을 의미한다. 우리가 ec2에 들어가서 해야 하는 작업들을 처리해준다고 보면 된다.
github action을 만들어보자.
그러면 다음과 같이 yml 파일 하나를 적어야 한다. 나는 배포를 위한 yml 파일이라는 뜻으로 deploy.yml 으로 이름을 지었다. 보통 main branch를 따라가는 듯 하고, workflows라는 파일 안에 만들어진다.
다음과 같이 작성한다.
name: Spring Boot & Gradle & Docker & EC2 CI/CD
on:
push:
branches:
- main
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest #ubuntu-20.04
steps:
# 기본 체크아웃
- name: Checkout
uses: actions/checkout@v3
## 1) git ignore에 등록된 application.properties 파일 생성해주기
- name: make application.properties
run: |
cd ./src/main/resources
touch ./application.yml
echo "${{ secrets.PROPERTIES }}" > ./application.yml
shell: bash
## 2) 스프링 프로젝트 jar 파일 빌드
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew clean build --no-daemon
## 3) Docker Hub에 이미지 push 하기
- name: Docker build
run: |
docker login -u ${{ secrets.USERNAME }} -p ${{ secrets.PASSWORD }}
docker build -t ${{ secrets.USERNAME }}/text-in-the-road-server:0.1 .
docker push ${{ secrets.USERNAME }}/text-in-the-road-server:0.1
## 4) Docker Hub에 Push한 이미지를 리눅스 서버에 받아와서 run
- name: Deploy
uses: appleboy/ssh-action@v0.1.8
with:
host: ${{ secrets.AWS_TEST_X_HOST }}
username: ${{ secrets.AWS_TEST_X_USERNAME }}
key: ${{ secrets.AWS_TEST_X_KEY }}
port: ${{ secrets.AWS_TEST_X_PORT }}
script: |
docker login -u ${{ secrets.USERNAME }} -p ${{ secrets.PASSWORD }}
docker rm $(docker ps -a -q)
docker rmi ${{ secrets.USERNAME }}/text-in-the-road-server:0.1
docker pull ${{ secrets.USERNAME }}/text-in-the-road-server:0.1
docker-compose up -d
변수 등록
${{secret. ~~}}에 관련한 내용들은 해당 respository settings에 secrets에 등록하면 된다. 다시 수정하게 되더라도 전에 썼던 내용들은 다른 사람들이 볼 수 없도록 만들어져 있으니 docker 이름이나 비밀번호를 다른 팀원이 볼까 걱정하지 않아도 된다!
※주의: secrets.<변수명> 에서 변수명은 무조건 대문자여야 한다.
.gitignore 생성
secrets를 이용하면, 변수 뿐만 아니라 gitignore에 있던 파일 내용 자체를 build시에 생성해 사용할 수 있다.
## 1) git ignore에 등록된 application.properties 파일 생성해주기
- name: make application.properties
run: |
cd ./src/main/resources
touch ./application.yml
echo "${{ secrets.PROPERTIES }}" > ./application.yml
shell: bash
./src/main/resources 폴더 안에 application.yml 파일을 만드는 로직이다. 이 파일에 있는 내용은 secrets.PROPERTIES 안에 넣으면 된다.
build로직
## 2) 스프링 프로젝트 jar 파일 빌드
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew clean build --no-daemon
우리는 querydsl을 사용하기 때문에 ./gradlew clean build --no-daemon 명령어를 사용해 이전 build시 캐시 조차 없애도록 구현했다. run에 있는 파일들이 실행된다고 생각하자.
docker와 연결
docker에 로그인하고 이미지를 build하는 로직이다.
## 3) Docker Hub에 이미지 push 하기
- name: Docker build
run: |
docker login -u ${{ secrets.USERNAME }} -p ${{ secrets.PASSWORD }}
docker build -t ${{ secrets.USERNAME }}/text-in-the-road-server:0.1 .
docker push ${{ secrets.USERNAME }}/text-in-the-road-server:0.1
팀에서 이미지를 공유하려고 한다면, Docker Hub를 사용한다.
docker hub에 로그인하고, 해당 로그인 아이디를 아래 코드에서 secrets.USERNAME으로 써야 한다. docker 명령어는 다른 환경에서 도커 이미지를 한 번 만들어보면서 이해하자!
ec2에 연결
docker 이미지를 ec2 환경에서 배포한다.
## 4) Docker Hub에 Push한 이미지를 리눅스 서버에 받아와서 run
- name: Deploy
uses: appleboy/ssh-action@v0.1.8
with:
host: ${{ secrets.AWS_TEST_X_HOST }}
username: ${{ secrets.AWS_TEST_X_USERNAME }}
key: ${{ secrets.AWS_TEST_X_KEY }}
port: ${{ secrets.AWS_TEST_X_PORT }}
script: |
docker login -u ${{ secrets.USERNAME }} -p ${{ secrets.PASSWORD }}
docker rm $(docker ps -a -q)
docker rmi ${{ secrets.USERNAME }}/text-in-the-road-server:0.1
docker pull ${{ secrets.USERNAME }}/text-in-the-road-server:0.1
docker-compose up -d
appleboy/ssh-action을 사용하였는데, 아주 편리하고 좋다.
변수에는
HOST: ec2 주소를 넣는다. ec2-13 ~~ 으로 시작하거나 퍼블릭 ip 주소(13.522.51.23 이런 형식)
USERNAME: ec2에서 ubuntu를 쓴다면 ubuntu 입력 ->다른 환경은 이 블로그를 확인하자!
KEY: ec2에서 key.pem을 다운받았을 텐데 그 파일을 메모장으로 열어 복붙해 넣는다. 아마 -----BEGIN RSA PRIVATE KEY-----로 시작할 거다!
PORT:SSH
포트를 뜻하는
22를 넣는다. 기본적으로 appleboy/ssh-action에서 22로 할당되어 있어 생략해도 된다.
Docker Compose
여러 컨테이너에서 web/app/db 등을 한 번에 처리하고 싶을 때 사용한다.
우리는 일단 server만 배포하는 환경이므로 아래처럼 docker-compose.yml을 작성하였다.
version: '3'
services:
spring:
container_name: spring
image: jeonyoungseo/text-in-the-road-server:0.1
expose:
- 8080
ports:
- 8080:8080
더 배울 것들
Jenkins - ssh에 대한 이해를 좀 더 하고 배우면 좋을 것 같다.
Kubernetes - ec2 와 비슷한 컨테이너 기반 플랫폼
Travis CI - 테스트 없이 자동 배포CI/CD가 무한으로 돌아갈 때 타임아웃을 해야 하나..??
'BackEnd > DEVOPS' 카테고리의 다른 글
[Serverless|Cloud RUN] Google Cloud Run으로 JAVA WAR 파일 배포하기 (2) | 2024.01.02 |
---|---|
[DEVOPS] Linux 환경에서 ELK metricbeat를 사용한 시스템 모니터링 (0) | 2023.09.02 |
[Kafka] Kafka 이론 및 실습(Window10 Local 환경) (0) | 2023.08.11 |
[DEVOPOS | AWS | SPRING] application.yml 파일 환경변수 외부주입 - aws env 파일/intellij configuration (1) | 2023.06.09 |
[DEVOPS] EC2+Docker로 배포해보기 (2) | 2023.02.09 |