3. Docker + ๋ฐฑ์๋(Spring Boot) ํ๋ก์ ํธ์ CI/CD ์ ์ฉํ๊ธฐ
- 2๊ฐ์ง ๋ฐฉ๋ฒ ์กด์ฌ
- Docker: ์ปจํ ์ด๋ ๊ธฐ๋ฐ ํ๋ก์ ํธ
- Docker, CodeDeploy: ์ปจํ ์ด๋ + ํ์ฅ์ฑ ๊ณ ๋ คํ ํ๋ก์ ํธ
1. Docker: ์ปจํ ์ด๋ ๊ธฐ๋ฐ ํ๋ก์ ํธ
- ์ ์ฒด ํ๋ฆ
- ์ฅ์
- Docker ๊ธฐ๋ฐ ์๋น์ค ์ด์ ์, ๊ฐ๋จํ๊ฒ ๊ตฌ์ฑ ๊ฐ๋ฅํ ์ธํ๋ผ ๊ตฌ์กฐ
- ๋จ์
- ๋ฌด์ค๋จ ๋ฐฐํฌ ๊ตฌํ or ์ฌ๋ฌ EC2์ ๋ฐฐํฌํด์ผ ํ๋ค๋ฉด, ์ง์ Github Actions์ ์คํฌ๋ฆฝํธ ์์ฑ, ๊ตฌํ ํ์ -> ๋ณต์ก
- ์ฌ์ฉ
- ์ปจํ ์ด๋ ๊ธฐ๋ฐ ์ธํ๋ผ ๊ตฌ์ฑ ์
- ์๊ท ๋ชจํ๋ก์ ํธ
์ค์ต 1
- EC2์ Docker ์ค์น, ECR ์ธํ
- Ubuntu์์ Docker, Docker Compose ์ค์น
$ sudo apt-get update && \
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && \
sudo apt-key fingerprint 0EBFCD88 && \
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && \
sudo apt-get update && \
sudo apt-get install -y docker-ce && \
sudo usermod -aG docker ubuntu && \
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
sudo chmod +x /usr/local/bin/docker-compose && \
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
# ์ ์ค์น๋๋ ์ง ํ์ธ
$ docker -v # Docker ๋ฒ์ ํ์ธ
$ docker compose version # Docker Compose ๋ฒ์ ํ์ธ
- Github Actions์ IAM์ ๊ถํ ์ถ๊ฐ
- AmazonEC2ContainerRegistryFullAccess ๊ถํ ์ถ๊ฐ
- ECR ์์ฑ
์ค์ต 2
- Docker ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์ ํธ ์์
- Dockerfile ์์ฑ
- .dockerignore ํ์ผ ์์ฑ
#Dockerfile
FROM node:alpine
WORKDIR /usr/src/app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
CMD [ "node", "dist/main.js" ]
#.dockerignore ํ์ผ
node_modules
- EC2๊ฐ private ECR์ ์ ๊ทผํ๋๋ก ์
ํ
- ECR Docker Credential Helper ์ค์น
- Configuration ์ค์
- IAM Role ํ์ฉํ์ฌ EC2์ ECR ์ ๊ทผ ๊ถํ ๋ถ์ฌ
- EC2์ ์ฐ๊ฒฐ๋ IAM Role์AmazonEC2ContainerRegistryFullAccess ์ ์ฑ ์ถ๊ฐ
# ECR Docker Credential Helper ์ค์น
# Ubuntu์ผ ๊ฒฝ์ฐ
$ sudo apt update
$ sudo apt install amazon-ecr-credential-helper
# Configuration ์ค์
# ~ ๊ฒฝ๋ก์์ .dockerf ํด๋ ๋ง๋ค๊ณ , config.json ํ์ผ ์์ฑ
# ~/.docker/config.json
{
"credsStore": "ecr-login"
}
- Docker ๊ธฐ๋ฐ์ผ๋ก CI/CD ๊ตฌ์ถ
- Github Actions ํ์ผ ์์ฑ
# .github/workflows/deploy.yml
name: Deploy To EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository ํ์ผ ๋ถ๋ฌ์ค๊ธฐ
uses: actions/checkout@v4
- name: Node ์ค์น
uses: actions/setup-node@v4
with:
node-version: "20"
- name: ์์กด์ฑ(๋ผ์ด๋ธ๋ฌ๋ฆฌ) ์ค์น
run: npm ci
- name: .env ํ์ผ ๋ง๋ค๊ธฐ
run: |
touch .env
echo '${{ secrets.ENV }}' >> .env
- name: ํ
์คํธ ์ฝ๋ ์คํ
run: npm run test
- name: AWS Resource์ ์ ๊ทผํ ์ ์๊ฒ AWS credentials ์ค์
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ap-northeast-2
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: ECR์ ๋ก๊ทธ์ธํ๊ธฐ
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Docker ์ด๋ฏธ์ง ์์ฑ
run: docker build -t instagram-server .
- name: Docker ์ด๋ฏธ์ง์ Tag ๋ถ์ด๊ธฐ
run: docker tag instagram-server ${{ steps.login-ecr.outputs.registry }}/instagram-server:latest
- name: ECR์ Docker ์ด๋ฏธ์ง Pushํ๊ธฐ
run: docker push ${{ steps.login-ecr.outputs.registry }}/instagram-server:latest
- name: SSH๋ก EC2์ ์ ์ํ๊ธฐ
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
script_stop: true
script: |
docker stop instagram-server || true
docker rm instagram-server || true
docker pull ${{ steps.login-ecr.outputs.registry }}/instagram-server:latest
docker run -d --name instagram-server -p 3000:3000 ${{ steps.login-ecr.outputs.registry }}/instagram-server:latest
2. Docker, CodeDeploy: ์ปจํ ์ด๋ + ํ์ฅ์ฑ ๊ณ ๋ คํ ํ๋ก์ ํธ
- ์ ์ฒด ํ๋ฆ
- ์ฅ์
- ์ปจํ ์ด๋ ๊ธฐ๋ฐ ์๋ฒ๊ฐ ์ฌ๋ฌ ๋์ด๋๋ผ๋ ์๋ ๋ฐฐํฌ ์ฉ์ด
- ๋ฌด์ค๋จ ๋ฐฐํฌ ์ ์ฉ ์ฉ์ด
- ๋จ์
- CodeDeploy ์ฌ์ฉ -> ์ธํ๋ผ ๊ตฌ์กฐ ๋ณต์ก
- ์ฌ์ฉ
- ์ปจํ ์ด๋ ๊ธฐ๋ฐ ์ธํ๋ผ ๊ตฌ์ฑ + ์ฌ๋ฌ ๋ + ๋ฌด์ค๋จ ๋ฐฐํฌ
์ค์ต
- Github Actions ์ฝ๋ ์์ ํ๊ธฐ
# .github/workflows/deploy.yml
name: Deploy To EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository ํ์ผ ๋ถ๋ฌ์ค๊ธฐ
uses: actions/checkout@v4
- name: JDK 17๋ฒ์ ์ค์น
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: application.yml ํ์ผ ๋ง๋ค๊ธฐ
run: echo "${{ secrets.APPLICATION_PROPERTIES }}" > ./src/main/resources/application.yml
- name: ํ
์คํธ ๋ฐ ๋น๋ํ๊ธฐ
run: ./gradlew clean build
- name: AWS Resource์ ์ ๊ทผํ ์ ์๊ฒ AWS credentials ์ค์
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ap-northeast-2
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: ECR์ ๋ก๊ทธ์ธํ๊ธฐ
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Docker ์ด๋ฏธ์ง ์์ฑ
run: docker build -t instagram-server .
- name: Docker ์ด๋ฏธ์ง์ Tag ๋ถ์ด๊ธฐ
run: docker tag instagram-server ${{ steps.login-ecr.outputs.registry }}/instagram-server:latest
- name: ECR์ Docker ์ด๋ฏธ์ง Pushํ๊ธฐ
run: docker push ${{ steps.login-ecr.outputs.registry }}/instagram-server:latest
- name: ์์ถํ๊ธฐ
run: tar -czvf $GITHUB_SHA.tar.gz appspec.yml scripts
- name: S3์ ํ๋ก์ ํธ ํด๋ ์
๋ก๋ํ๊ธฐ
run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.tar.gz s3://instagram-server/$GITHUB_SHA.tar.gz
- name: Code Deploy๋ฅผ ํ์ฉํด EC2์ ํ๋ก์ ํธ ์ฝ๋ ๋ฐฐํฌ
run: aws deploy create-deployment
--application-name instagram-server
--deployment-config-name CodeDeployDefault.AllAtOnce
--deployment-group-name Production
--s3-location bucket=instagram-server,bundleType=tgz,key=$GITHUB_SHA.tar.gz
- appspec.yml, ์คํฌ๋ฆฝํธ ํ์ผ ์์
- appspec.yml -> ์ฝ๋ ์ ์ง
- scripts/start-server.sh
# appspec.yml -> ์ฝ๋ ์ ์ง
version: 0.0
os: linux
files:
# CodeDeploy๊ฐ S3๋ก๋ถํฐ ๊ฐ์ ธ์จ ํ์ผ ์ค destination์ผ๋ก ์ด๋์ํฌ ๋์์ ์ง์ ํ๋ค.
# / ์ด๋ผ๊ณ ์ง์ ํ๋ฉด S3๋ก๋ถํฐ ๊ฐ์ ธ์จ ์ ์ฒด ํ์ผ์ ๋ปํ๋ค.
- source: /
# CodeDeploy๊ฐ S3๋ก๋ถํฐ ๊ฐ์ ธ์จ ํ์ผ์ EC2์ ์ด๋ค ๊ฒฝ๋ก์ ์ ์ฅํ ์ง ์ง์ ํ๋ค.
destination: /home/ubuntu/instagram-server
permissions:
- object: /
owner: ubuntu
group: ubuntu
hooks:
ApplicationStart:
- location: scripts/start-server.sh
timeout: 60
runas: ubuntu
# scripts/start-server.sh
#!/bin/bash
echo "--------------- ์๋ฒ ๋ฐฐํฌ ์์ -----------------"
docker stop instagram-server || true
docker rm instagram-server || true
docker pull {ECR Repository ์ฃผ์}/instagram-server:latest
docker run -d --name instagram-server -p 8080:8080 {ECR Repository ์ฃผ์}/instagram-server:latest
echo "--------------- ์๋ฒ ๋ฐฐํฌ ๋ -----------------"
4. ๋ฐฑ์๋(Nest.js) ํ๋ก์ ํธ์ CI/CD ์ ์ฉํ๊ธฐ
5. Docker + ๋ฐฑ์๋(Nest.js) ํ๋ก์ ํธ์ CI/CD ์ ์ฉํ๊ธฐ
6. ํ๋ก ํธ์๋ CI/CD ๊ตฌ์ฑ์ ์ํด ํ์ํ ๊ธฐ๋ณธ AWS ์ง์ (๋ณด์ถฉ ๊ฐ์)
7.์น ํ๋ก ํธ์๋ ํ๋ก์ ํธ์ CI/CD ์ ์ฉํ๊ธฐ
S3
- ๊ธฐ๋ฅ
- ํ์ผ ์ ์ฅ
- ์ ์ ์น ์ฌ์ดํธ ํธ์คํ = ์น ์๋น์ค๋ฅผ ์ธํฐ๋ท์ ๋ฐฐํฌ
- ๋ฒํท: ๊นํ๋ธ์ Repository์ฒ๋ผ S3์ ์ ์ฅ์
- ์ ์ฑ : ๊ถํ ์ ์ JSON ๋ฌธ์
- ex) ๋ฒํท์์ ์ด๋ฏธ์ง ํ์ผ์ ์กฐํํ ์ ์๋ ์ ์ฑ ์ ์ถ๊ฐํ๋ค.
- ๊ฐ์ฒด: S3์ ์ ๋ก๋ํ ํ์ผ
CloudFront
- CDN(Content Delivery Network)
- ๊ธฐ๋ฅ: ํ์ผ, ๋์์ ๋ฑ์ ์ปจํ ์ธ ๋ฅผ ๋น ๋ฅด๊ฒ ์ ์ก ํด์ฃผ๋ ์๋น์ค
- ๊ฐ๊น์ด ์์น์ ์ปจํ ์ธ ์ ๋ณต์ฌ๋ณธ์ ์ ์ฅํ์ฌ ์์ ์ ์ฅ์๋ก ์ฌ์ฉ
- ๋ฌด์๋ณด๋ค HTTPS๋ฅผ ์ ์ฉํ๊ธฐ ์ํด์๋ CloudFront๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
S3 ๋ฒํท ์ธํ
S3 ๋ฒํท ์์ฑ
- S3 -> ๋ฒํท ๋ง๋ค๊ธฐ -> ๋ฒํท ์ด๋ฆ ์ง์ ํ๊ณ -> ์ด ๋ฒํท์ ํผ๋ธ๋ฆญ ์ก์ธ์ค ์ฐจ๋จ์ ๋ชจ๋ ๋นํ์ฑํํด์ผํ๋ค(์ด ํ์ด์ง ์ ์ํด์ ๋ค์ด๋ฐ๋ ๋ชจ๋ ์ฌ์ฉ์๊ฐ ๋ค์ด๋ฐ์ ์ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์) -> ๋ฒํท ๋ง๋ค๊ธฐ
๋ฒํท์ ์ ์ฑ ์ถ๊ฐํ๊ธฐ
- ๊ถํ -> ๋ฒํท ์ ์ฑ -> ํธ์ง -> ์ ๋ฌธ ์ถ๊ฐ -> S3๊ฒ์ -> GetObject -> ๋ฆฌ์์ค ์ถ๊ฐ(์๋น์ค:S3, ๋ฆฌ์์ค ์ ํ:object, ๋ฆฌ์์ค ARN:arn:aws:s3:::{๋ด๊ฐ ๋ง๋ ๋ฒํท๋ช }/*) -> ์ ์ฑ ์์ Principal์ "*"๋ก ๋ณ๊ฒฝ -> ์ ์ฅ
S3์ ์ ๋ก๋
S3์ ์ ๋ก๋
- ํ ์คํธ ์ํ ๊ฐ๋จํ ํ์ผ์ ๋ง๋ ๋ค.
- index.html
<h1>Title</h1>
- Amazone S3 -> ๋ฒํท -> ๋ฒํท์ด๋ฆ -> ํ์ผ ๋๋๊ทธํด์ ์ ๋ก๋
- ๋ฒํท ๋ค์ด๊ฐ์ ์ ๋ก๋ ๋๋ฅด๋ฉด ์ฌ๋ผ๊ฐ๊ฒ ํ์ธ ๊ฐ๋ฅ
S3์ ์ ์ ์น ํธ์คํ ์ค์
- ๋ฒํท -> ์์ฑ -> ๋ฐ์ ์ ์ ์น ์ฌ์ดํธ ํธ์คํ -> ํธ์ง -> ํ์ฑํ, ์ ์ ์น ์ฌ์ดํธ ํธ์คํ ์ ํ -> ์ธ๋ฑ์ค ๋ฌธ์: index.html -> ์ ์ฅ
- ๋งจ ๋ฐ์ ์๋ก์ด ๋งํฌ๊ฐ ์๊ธด๊ฒ ํ์ธ ๊ฐ๋ฅ
์ด์ ์ฑ๋ฅ ๋ฌธ์ ์, https ์ ์ฉ์ ์ํด์ CloudFront๋ฅผ ์ ์ฉํด๋ณด์
CloudFront ์์ฑ
- CloudFront -> ๋ฐฐํฌ์์ฑ -> ์๋ณธ ๋๋ฉ์ธ ์ ๋ ฅ -> ์ด๋ S3 ๋ฒํท ์๋ํฌ์ธํธ๋ง๊ณ S3 ์ ์ ํธ์คํ ์น ์ฌ์ดํธ ์๋ํฌ์ธํธ ์ ํ-> HTTP,HTTPS์ ๋ํ ์ ์ฑ ์ ํ: Redirect HTTP to HTTPS -> WAF ์ค์ : ๋ณด์ ๋ณดํธ ๋นํ์ฑํ -> ์ค์ -> ๊ฐ๊ฒฉ๋ถ๋ฅ ์ค์ : ๋ถ๋ฏธ, ์ ๋ฝ, ์์์, ์ค๋ ๋ฐ ์ํ๋ฆฌ์นด์์ ์ฌ์ฉ -> ๊ธฐ๋ณธ๊ฐ ๋ฃจํธ ๊ฐ์ฒด: index.html -> CloudFront ๋ฐฐํฌ ์์ฑ -> ํ์ธ
- ์ฐ๋ฆฌ๋ S3์ ์ฃผ์๊ฐ ์๋๋ผ CloudFront์ ์ฃผ์๋ฅผ ์์์ผ ํ๋ค. ์ด๋, ๋ฐฐํฌ ๋๋ฉ์ธ ์ด๋ฆ์ด CloudFront์ ์ฃผ์
์ด์ CloudFront์ ๋๋ฉ์ธ์ ์ฐ๊ฒฐํ๊ณ , HTTPS๋ฅผ ์ ์ฉํ๋ฉด ๋๋ค.
์ถ์ฒ
๋น์ ๊ณต์๋ ์ดํดํ ์ ์๋ CI/CD ์ ๋ฌธ·์ค์ ๊ฐ์ | JSCODE ๋ฐ์ฌ์ฑ - ์ธํ๋ฐ
JSCODE ๋ฐ์ฌ์ฑ | ๋น์ ๊ณต์ ์ ์ฅ์์๋ ์ฝ๊ฒ ์ดํดํ ์ ์๊ณ , ์ค์ ์์ ๋ฐ๋ก ์ ์ฉ ๊ฐ๋ฅํ CI/CD ์ ๋ฌธ ๊ฐ์๋ฅผ ๋ง๋ค์ด๋ดค์ต๋๋ค!, ๐คฌ ์๋ผ์ด, ๋ชป ํด๋จน๊ฒ ๋ค!๋น์ ๊ณต์๋ก ๊ฐ๋ฐ์ ์์ํด ์ฌ๋ฌ ํ์ฌ์์ CTO๋ก
www.inflearn.com
'๐ณ์ธํ๋ผ > Cloud & CI-CD' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
EC2, ECR, Docker Compose, Github Actions ์ฌ์ฉํ์ฌ SpringBoot, MongoDB ๋ฐฐํฌํ๊ธฐ (1) | 2024.10.01 |
---|---|
๋น์ ๊ณต์๋ ์ดํดํ ์ ์๋ CI/CD ์ ๋ฌธ/์ค์ (1) (0) | 2024.09.23 |