์ด์ ์ ์งํํ๋ ํ๋ก์ ํธ๋๋ ๊ทธ๋ ๊ณ ์ด๋ฒ ํ๋ก์ ํธ์๋ ci-cd ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ๋๋ฐ github action, AWS S3, AWS CODEDEPLOY ๋ฅผ ์ฌ์ฉํ๋ค.
์ํํธ์จ์ด ์ํคํ ์ฒ๋ ์๋์ ๊ฐ์ด ๊ตฌ์ฑํ์๋ค.
ํ์ง๋ง ์ด๋ ์ธํ ๊ณผ์ ์ด ๋๋ฌด ๊ธธ๊ณ ๋ณต์กํ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
๋ ์ข์ ๋ฐฉ๋ฒ์ด ์์๊น ์ฐพ์๋ณด๋ค Docker๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ํ๊ณ ์ด์ ๊ณผ ๋ฌ๋ฆฌ ๋๋ฌด ํธํด์ง ํ์ดํ๋ผ์ธ ๊ตฌ์ถ ๊ณผ์ ์ ๊ธฐ๋กํ๊ธฐ ์ํด ๊ธ์ ์ด๋ค.
๊ทธ ์ ์ cicd์ ๋ํด ์์๋ณด์
CICD ๋ ๋ฌด์์ธ๊ฐ?
CI/CD๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ ๋จ๊ณ๋ถํฐ ๋ฐฐํฌ ๋๊น์ง์ ๋ชจ๋ ๋จ๊ณ๋ฅผ ์๋ํ๋ฅผ ํตํด์ ์ข ๋ ํจ์จ์ ์ด๊ณ ๋น ๋ฅด๊ฒ ์ฌ์ฉ์์๊ฒ ๋น๋ฒํ ๋ฐฐํฌํ ์ ์๋ ๊ฒ์ ๋งํ๋ค.
CI (Continuous Integration)
CI (Continuous Integration)๋ "์ง์์ ์ธ ํตํฉ"์ด๋ผ๋ ์๋ฏธ์ด๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฒ๊ทธ ์์ ์ด๋ ์๋ก์ด ์ฝ๋ ๋ณ๊ฒฝ์ด ์ฃผ๊ธฐ์ ์ผ๋ก ๋น๋ ๋ฐ ํ ์คํธ๋๋ฉด์ ๊ณต์ ๋๋ ๋ ํ์งํ ๋ฆฌ์ ํตํฉ(merge)๋๋ ๊ฒ์ ์๋ฏธํ๋ค.
์ฃผ๊ธฐ์ ์ผ๋ก ๋น๋ฒํ๊ฒ ๊ณต์ ํ์ง ์์ผ๋ฉด ์ ์ ๋ ๊น??
์๋ฅผ ๋ค์ด ์ฌ๋ฌ ๋ช ์ด์ ํ๋ก์ ํธ๋ฅผ ์งํํ๊ณ ์๊ณ , ํ์๊ด๋ฆฌ ๋๊ตฌ๋ก git ์ ์ฌ์ฉํ๊ณ ์๋ค ๊ฐ์ ํ์. ์ด๋ค์ด ์์ฃผ mergeํ์ง ์๊ณ 2์ผ 3์ผ ํน์ ๋ ์ค๋ ๊ธฐ๊ฐ ๋์ ๊ฐ๋ฐ์ ์งํํ๋ค๊ฐ ๋ฉฐ์น ๋์ ์์ ํ ๋ง์ ์ฝ๋๋ค์ ํ ๋ฒ์ merge ํ๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น? ๐ค
๋ง์ ์ถฉ๋์ด ์ผ์ด๋ ๊ฒ์ด๊ณ ์ถฉ๋ ํด๊ฒฐ ๊ณผ์ ์ ์๋ ์๊ฐ์ด ๋ง์์ง ๊ฒ์ด๋ค. ์์ฐ์ค๋ฝ๊ฒ ๊ฐ๋ฐ ํจ์จ์ฑ์ ๋จ์ด์ง๊ฒ ๋๋ค.
๊ทธ๋ ๊ธฐ์, ๊ฐ๋ฅํ ์์ ๋จ์๋ก ๋๋์ด์ ์ฃผ๊ธฐ์ ์ผ๋ก ๋น๋ฒํ ๊ฐ๋ฐํ๊ณ ๊ณ์ํด์ ํตํฉํ์ฌ ๋๊ฐ๋ ๊ฒ์ด ์ค์ํ๋ค.
์์ฃผ mergeํ์!
๋ค ์ข์๋ฐ mergeํ ๋๋ง๋ค buildํ๊ณ testํ๋ ๊ณผ์ ๋ค์ด ๊ท์ฐฎ๋ค.
ํ์ง๋ง, ์ฌ๊ธฐ์ ์๋ํ๋ฅผ ์ฌ์ฉํด ์ค๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น? github์ ์ฝ๋๋ง ์ฌ๋ฆฌ๊ณ ๋๋จธ์ง ์์ ์ธ ํ ์คํธ์ ๋น๋๋ ํ๋ก๊ทธ๋จ์ด ์๋์ผ๋ก ํด์ค๋ค๋ฉด ๋ง์ ์๊ณ ๋ฅผ ๋ ๊ฒ์ด๋ค.
CD (Continuous Delivery)
CD๋ Continuous Delivery, ์ง์์ ์ธ ์ ๊ณต์ด๋ผ๋ ์๋ฏธ์ Continuous Deployment, ์ง์์ ์ธ ๋ฐฐํฌ๋ผ๋ ์๋ฏธ๊ฐ ์๋ค.
์ ๋ฆฌํ์๋ฉด, CI๊ฐ ์๋ก์ด ์์ค์ฝ๋์ ๋น๋, ํ ์คํธ, ๋ณํฉ๊น์ง๋ฅผ ์๋ฏธํ์๋๋ฐ, CD๋ ๊ฐ๋ฐ์์ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ๋์ด, ๊ณ ๊ฐ์ ํ๋ก๋์ (Production) ํ๊ฒฝ๊น์ง ๋ฆด๋ฆฌ์ฆ ๋๋ ๊ฒ์ ์๋ฏธํ๋ค.
๋ณธ๊ฒฉ์ ์ผ๋ก ๊ตฌ์ถ ๊ณผ์ ์ ๋ํด ์์๋ณด์
1. Dockerfile ์์ฑ
FROM
FROM์ ๊ธฐ๋ณธ ์ด๋ฏธ์ง๋ฅผ ์ง์ ํด์ค๋ค.
์ด๋ฏธ์ง ์ด๋ฆ์ด openjdk์ด๊ณ ํ๊ทธ๊ฐ 17-alpine์ธ ์ด๋ฏธ์ง๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๊ฒ ๋ค๋ ๋ป์ด๋ค.
์์ ์ ๋ฒ์ ์ ๋ง๊ฒ ์ด๋ฏธ์ง๋ฅผ ์ ํํ๋ฉด ๋๋ค.
ARG
๊ทธ๋ฆฌ๊ณ ARG๋ฅผ ํตํด์ jar ํ์ผ์ ์์น๋ฅผ ์ง์ ํด์คฌ๋ค.
jar ํ์ผ์ ์์ฑํ๊ณ ๋๋ฉด build/libs์ ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ build/libs/*.jar๊ฐ ์์ฑ๋ jar ํ์ผ์ ๊ฒฝ๋ก๊ฐ ๋๋ค.
์ฐธ๊ณ ๋ก gradle ๋น๋ ์ ์ผ๋ฐ์ ์ธ jar ํ์ผ๊ณผ plain์ด ๋ถ์ jar ํ์ผ์ด ์์ฑ๋๋ค๋ฉด plain jar ํ์ผ์ด ์์ฑ๋์ง ์๋๋ก ์ค์ ํ๋ ๊ฒ์ด ์ข๋ค.
build.gradle์ ๋ค์ ์ฝ๋๋ฅผ ์์ฑํด์ฃผ๋ฉด jar ํ์ผ์ด ํ๋๋ง ์๊ธธ ๊ฒ์ด๋ค.
COPY
jar ํ์ผ์ ์ปจํ ์ด๋ ๋ด๋ถ๋ก ๋ณต์ฌํ๋ค.
COPY [์์ฑ๋ ๋ก์ปฌ jar ํ์ผ ๊ฒฝ๋ก] [์ปจํ ์ด๋ ๋ด๋ถ jar ํ์ผ ๊ฒฝ๋ก]
ENTRY POINT
entry point๋ฅผ ํตํด ์ปจํ ์ด๋๋ฅผ ์คํํ๋ฉด ์๋์ผ๋ก jar ํ์ผ์ ์คํํ๋๋ก ํ๋ค.
ENTRYPOINT ["java","-Duser.timezone=Asia/Seoul","-Dspring.profiles.active=prod", "-jar","/app.jar"]
๋๊ฐ์ ๊ฒฝ์ฐ์ timezone์ ์์ธ๋ก ์ค์ ํด์คฌ๊ณ profile ์ prod๋ก ์ก๊ณ jar ํ์ผ์ ์คํํ ์ ์๋๋ก ํ๋ค.
์ต์ ์ ๊ฐ ์ํฉ์ ๋ง๊ฒ ์ฌ์ฉํ๋ฉด ๋๋ค.
2. docker-compose.yml ์์ฑ
DB๋ AWS RDS๋ฅผ ์ฌ์ฉํด ๋ฐ๋ก ๋นผ๋์๊ธฐ ๋๋ฌธ์ redis์ Spring๋ง ๋์ด์ฃผ์๋ค.
docker-compose๋ ์คํํ ๋ .envํ์ผ์ ์ฝ๊ธฐ ๋๋ฌธ์ .envํ์ผ์ ๋ฐ๋ก ์ธํ ํด๋์๋ค.
.envํ์ผ์ ๋ฌผ๋ก docker-compose.ymlํ์ผ๊ณผ ๊ฐ์ ๋ฃจํธ์ ๋๋ฌ์ผ ํ๋ค. (๋์ ๊ฒฝ์ฐ์ ec2 ์ /home/ubuntu์ ๋ )
restart: always ๋ ์ปจํ ์ด๋๊ฐ ์ด๋ค ์ด์ ๋ก๋ ์ค์ง๋๋ฉด(ex. ์ค๋ฅ), ์๋์ผ๋ก ๋ค์ ์์ํ์ฌ ์์ฉ ํ๋ก๊ทธ๋จ์ ๊ฐ์ฉ์ฑ์ ์ ์งํ ์ ์๋๋ก ํ๋ ์ต์ ์ด๋ค.
redis ์ ๋ฐ์ดํฐ๋ค์ ์ปจํ ์ด๋๋ฅผ ์ฌ์์ํด๋ ์ ์ง๋์ผ ํ๊ธฐ ๋๋ฌธ์ volume์ ์ก์ ๋์๋ค.
logging ๋ถ๋ถ์ cloud watch์ ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํด๋๊ธฐ ์ํด ์ฌ์ฉํ๋๋ฐ, ci/cd์๋ ๊ด๋ จ ์๋ค.
version: "3.8"
services:
redis:
image: redis:latest
container_name: redis
hostname: redis
ports:
- "6379:6379"
volumes:
- ./redis/data:/data
spring:
container_name: spring
image: ${DOCKERHUB_USERNAME}/jikgong
depends_on:
- redis
environment:
- DB_ENDPOINT=${DB_ENDPOINT}
- DB_PASSWORD=${DB_PASSWORD}
- DB_USERNAME=${DB_USERNAME}
- SECRET_KEY=${SECRET_KEY}
- S3_ACCESS_KEY=${S3_ACCESS_KEY}
- S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY}
- FCM_PATH=${FCM_PATH}
logging:
driver: awslogs
options:
awslogs-group: ...
awslogs-region: ...
awslogs-stream: ...
ports:
- "8080:8080"
restart: always
3. .github/workflows/deploy.yml ์์ฑ
github action์์ ์ํํ ๋์๋ค์ deploy.yml ํ์ผ์ ์์ฑํด์ฃผ์๋ค.
name: Java CI with Gradle
on:
push:
branches: [ "release" ]
permissions:
contents: read
jobs:
build-docker-image:
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: Run chmod to make graldew executable
run: chmod +x ./gradlew
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
with:
arguments: clean bootJar -Pspring.profiles.active=prod
- name: docker image build
run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/jikgong .
- name: docker login
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: docker Hub push
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/jikgong
cd-pipeline:
needs: build-docker-image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: copy file via ssh password
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ubuntu
password: ${{ secrets.SSH_PASSWORD }}
port: 22
source: "./docker-compose.yml"
target: "/home/ubuntu/"
- name: executing remote ssh commands using password
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ubuntu
password: ${{ secrets.SSH_PASSWORD }}
port: 22
script: |
sudo docker rm -f $(docker ps -qa)
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/jikgong
sudo docker-compose up -d
sudo docker image prune -f
์ฒซ๋ฒ์งธ JOB - build-docker-image
uses: actions/checkout@v3
- ํ์ฌ ์ํฌ์คํ์ด์ค(๋ ํฌ์งํ ๋ฆฌ)์ ๋ํ ์์ค ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๊ณ ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ์ง์ ๋ ๋ธ๋์น ๋๋ ์ปค๋ฐ์ผ๋ก ์ค์
name: docker image build
- ๋์ปค ์ด๋ฏธ์ง ๋น๋. ์์์ ์์ฑํ Dockerfile์ ์ฌ๊ธฐ์ ์ฝ์ด๋ค์ธ๋ค.
name: docker login
- ๋์ปค ํ๋ธ์ ๋ก๊ทธ์ธ์ ํด์ค๋ค. ์ด๋ username๊ณผ token์ ์ฌ์ฉํ์ฌ ๋ก๊ทธ์ธ ํ๋๋ฐ token์ docker hub ์ฌ์ดํธ์์ ๋ฐ๊ธ ๊ฐ๋ฅํ๋ค.
name: docker Hub push
- docker hub ์ push ํด์ค๋ค. ๋ฐ๋ก ํ๊ทธ๋ฅผ ์ง์ ํด์ฃผ์ง ์์๊ธฐ ๋๋ฌธ์ latest๋ก ์๋ ์ง์ ๋๋ค.
๋๋ฒ์งธ JOB - cd-pipeline
needs: build-docker-image
- build-docker-image์ job์ด ์๋ฃ๋ ๋ ๊น์ง ๋๊ธฐํ๋ค.
copy file via ssh password
- SSH ๋ฅผ ์ด์ฉํ์ฌ file ์ ec2๋ก ์ด๋
- host: ์๊ฒฉ ์๋ฒ์ ํธ์คํธ ์ฃผ์(IP ์ฃผ์ ๋๋ ๋๋ฉ์ธ ์ด๋ฆ)
- username: SSH ์ฐ๊ฒฐ์ ์ํด ์ฌ์ฉ๋๋ ์๊ฒฉ ์๋ฒ์ ๊ณ์ ์ด๋ฆ (ec2๋ฅผ ๋ง๋ค ๋ ubuntu ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ubuntu ์ด๋ค.)
- password: SSH ์ฐ๊ฒฐ์ ์ํ ๋น๋ฐ๋ฒํธ. ec2์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ๋ก ์ค์ ํด์ผ ํจ
- port: SSH ์๋ฒ๊ฐ ์ฌ์ฉํ๋ ํฌํธ ๋ฒํธ. ์ผ๋ฐ์ ์ผ๋ก 22๋ฒ ํฌํธ๊ฐ ์ฌ์ฉ
- source: ๋ก์ปฌ์์ ๋ณต์ฌํ ํ์ผ ๋๋ ๋๋ ํ ๋ฆฌ์ ๊ฒฝ๋ก.
- target: ์๊ฒฉ ์๋ฒ์ ๋ณต์ฌํ ๊ฒฝ๋ก.
executing remote ssh commands using password
- ์์ฑํ ์คํฌ๋ฆฝํธ ๋ช ๋ น์ด ์คํ
- ์คํ์ค์ธ ์คํ๋ง, ๋ ๋์ค ์ปจํ ์ด๋๋ฅผ ์ข ๋ฃํ๊ณ docker compose ์คํ
'devOps ๐ก' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Prometheus & Grafana ๋ฅผ ํตํด ๋ชจ๋ํฐ๋ง์ ํด๋ณด์ (Spring boot) (2) | 2024.01.22 |
---|---|
๋ฌด์ค๋จ ๋ฐฐํฌ ์ ์ฉํ๊ธฐ (SpringBoot, Docker, Nginx, GithubAction) (1) | 2023.12.27 |
๋ฐฐํฌ ๊ณผ์ ์์ ์์๋ ์ผ๋ค (1) | 2023.10.07 |
[GIT] Git Flow | Github Flow ์ ๋ต (1) | 2023.08.24 |
Github Action ๋ฐฐํฌ ์๋ํ ํ์ดํ๋ผ์ธ ๊ตฌ์ถ A-Z (0) | 2023.08.24 |