[따라하며 배우는 도커와 CI환경] 9. 복잡한 어플을 실제로 배포해보기(테스트 & 배포 부분)
이제 소스코드를 테스트한 후 테스트 성공 시, AWS를 통해 배포하는 부분을 추가할 것이다.
애플리케이션을 배포하는 과정은 다음과 같다.
Travis CI에서 바로 AWS Elastic Beanstalk으로 전달하지 않고, Docker Hub에 빌드된 이미지를 보관함으로써 이미지를 한 번만 빌드하도록 한다.
✔️ Github 에 소스코드 업로드
1️⃣ github에서 repository 생성하기
2️⃣ 로컬 git 저장소 만들기
$ git init
3️⃣ .gitignore 파일 추가
node_modules
mysql_data
4️⃣ 커밋하기
$ git add .
$ git commit -m "first commit"
5️⃣ remote 저장소에 push 하기
- 처음에는 remote 저장소를 추가한 후, push 한다.
$ git remote add origin <repo 주소>
$ git push origin master
✔️ Travis CI 설정
1️⃣ github 계정으로 로그인하기
2️⃣ repository 추가하고 활성화하기
- Settings > Repositories 에서 Activate 버튼 클릭
- Repository access에서 생성한 repostiory 선택 후, Approve and install 버튼 클릭
3️⃣ 환경변수 추가하기
- More options > Settings 에서 환경 변수를 추가한다.
- 도커 아이디와 비밀번호를 각각
DOCKER_HUB_ID
,DOCKER_HUB_PASSWORD
라는 이름으로 저장한다.
4️⃣ .travis.yml 파일 작성하기
language: generic
sudo: required
services:
- docker
before_intall:
- docker build -t <docker hub id>/react-test-app -f ./frontend/Dockerfile.dev ./frontend
script:
- docker run -e CI=true <docker hub id>/react-test-app npm run test
after_success:
- docker build -t <docker hub id>/docker-frontend ./frontend
- docker build -t <docker hub id>/docker-backend ./backend
- docker build -t <docker hub id>/docker-nginx ./nginx
- echo "$DOCKER_HUB_PASSWORD" | docker login -u "$DOCKER_HUB_ID" --password-stdin
- docker push <docker hub id>/docker-frontend
- docker push <docker hub id>/docker-backend
- docker push <docker hub id>/docker-nginx
echo "$DOCKER_HUB_PASSWORD" | docker login -u "$DOCKER_HUB_ID" --password-stdin
:
도커 허브에 로그인한다. 도커 허브에 이미지를 push 하려면, 먼저 로그인을 수행해야 하고, 아이디와 비밀번호는 Travis CI의 환경변수로 설정해주었다.docker push <docker hub id>/<image name>
: 빌드 성공한 이미지를 도커 허브에 push한다.
+) 깃허브에 푸시 하기 전에, frontend/src/App.test.js를 수정해야 한다.
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {});
5️⃣ 커밋 & 푸시
master 브랜치에 푸시하면, 자동으로 Travis CI에서 테스트를 실행하고, 테스트 성공 시 도커 이미지를 생성 후 docker hub에 푸시한다.
도커 허브에 이미지가 추가된 것을 확인할 수 있다!
✔️ AWS에 배포하기
1️⃣ Elastic Beanstalk
📌 환경 생성하기
나는 docker-fullstack-app 이라는 이름으로 애플리케이션을 생성하였다.
플랫폼은 다음과 같이 설정하고, 환경을 생성한다.
📌 환경 변수
환경의 구성을 클릭하고 소프트웨어 편집 버튼을 클릭한다.
여기에 환경 속성을 추가하여 환경 변수를 설정한다.
MYSQL_HOST는 뒷부분에 나오는 RDS의 엔드포인트로 작성한다.
2️⃣ VPC, Security Group 설정
Elastic Beanstalk 환경을 생성하면, 자동으로 vpc가 생성된다.
이제 Security Group을 생성하여, 같은 VPC 안에 있는 AWS 서비스 간에는 트래픽을 모두 허용할 수 있도록 설정하자.
📌 보안 그룹 생성
VPC > 보안 > 보안 그룹 에서, 보안 그룹을 생성한다.
생성한 보안 그룹에 인바운드 규칙을 추가한다.
포트 번호를 3306번으로 하고, 소스는 방금 생성한 보안 그룹으로 설정한다.
📌 Elastic Beanstalk에 보안 그룹 추가
환경의 구성을 클릭하고 인스턴스의 편집 버튼을 클릭한다.
이제 여기에 새로 생성한 보안 그룹을 추가한다.
3️⃣ RDS
📌 docker-compose.yml 수정
- backend 부분에 db 관련 설정 추가
backend:
build:
dockerfile: Dockerfile.dev
context: ./backend
container_name: app_backend
volumes:
- /app/node_modules
- ./backend:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_ROOT_PASSWORD: 1234
MYSQL_DATABASE: myapp
MYSQL_PORT: 3306
📌 backend/db.js 수정
- 환경변수로 db pool 생성하도록 수정한다.
const mysql = require('mysql');
const pool = mysql.createPool({
connectionLimit: 10,
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_ROOT_PASSWORD,
database: process.env.MYSQL_DATABASE,
port: process.env.MYSQL_PORT
});
exports.pool = pool;
📌 rds 생성
표준 생성, MySQL을 선택하고 자격 증명 설정에서 마스터 사용자 이름(ex. root)과 마스터 암호를 설정한다.
초기 데이터베이스 이름(ex. myapp)도 설정해준다.
📌 rds에 보안그룹 적용
생성된 rds를 수정 버튼을 눌러, 위에서 생성한 보안 그룹을 추가한다.
📌 IAM USER 생성
액세스 유형: 프로그래밍 방식 액세스
권한 설정: 기존 정책 직접 연결 > AdministratorAccess-AWSElasticBeanstalk 를 선택
계정 생성 후 발급되는 액세스 키 ID와 비밀 액세스 키를 Travis CI의 환경 변수로 저장한다.
📌 .travis.yml 수정 (배포 부분 추가)
.travis.yml 파일에 다음을 추가한다.
deploy:
provider: elasticbeanstalk
region: "ap-northeast-2"
app: "docker-fullstack-app"
env: "Dockerfullstackapp-env"
bucket_name: "elasticbeanstalk-ap-northeast-2-230637774399"
bucket_path: "docker-fullstack-app"
on:
branch: master
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_ACCESS_KEY
4️⃣ docker-compose.yml 수정
- rds를 데이터베이스로 사용하므로 mysql을 주석 처리한다.
- elastic beanstalk에서 docker 앱을 사용하려면, 도커 이미지(
image
)와 메모리 사이즈(mem_limit
), 포트매핑(ports
), 연결할 컨테이너 목록(links
) 등을 추가해야 한다.
version: "3"
services:
frontend:
image: <docker hub id>/docker-frontend
volumes:
- /app/node_modules
- ./frontend:/app
stdin_open: true
mem_limit: 128m
nginx:
restart: always
image: <docker hub id>/docker-nginx
ports:
- "80:80"
mem_limit: 128m
links:
- frontend
- backend
backend:
image: <docker hub id>/docker-backend
container_name: app_backend
volumes:
- /app/node_modules
- ./backend:/app
environment:
MYSQL_HOST: <rds 엔드포인트>
MYSQL_USER: root
MYSQL_ROOT_PASSWORD: <rds 비밀번호>
MYSQL_DATABASE: myapp
MYSQL_PORT: 3306
mem_limit: 128m
# mysql:
# build: ./mysql
# restart: unless-stopped
# container_name: app_mysql
# ports:
# - "3306:3306"
# volumes:
# - ./mysql/mysql_data:/var/lib/mysql
# - ./mysql/sqls/:/docker-entrypoint-initdb.d/
# environment:
# MYSQL_ROOT_PASSWORD: 1234
# MYSQL_DATABASE: myapp
참고