본문 바로가기

Docker, CI

Docker - Node +Mysql + React - AWS 배포하기(Travis CI)

반응형

loy124.tistory.com/360

 

Docker - Node +Mysql + React - 개발및 Dockerfile 생성하기

github.com/loy124/docker-react-fullstack loy124/docker-react-fullstack Contribute to loy124/docker-react-fullstack development by creating an account on GitHub. github.com 풀스택 어플리케이션 선행..

loy124.tistory.com

전편에 이어 이제 배포가 남았다. 

배포는 github에 push -> main branch -> travis CI(테스트 실행 -> 테스트 성공 -> Dockerfile을 이용한 빌드) -> docker hub

-> AWS ElasticBeanStalk 식으로 진행이 된다. 

 

 

mysql 파트는 Docker 환경이 아닌 AWS RDS 를 활용하기 때문에 전편의 mysql파트를 수정해준다. 

 

1차적으로 docker-compose.yml에서 mysql파트가 동작하지 않도록 mysql 파트를 주석처리해준다. 

 

version: "3"
services: 
  frontend:
    build:
      dockerfile: Dockerfile.dev
      context: ./frontend
    #코드 수정후 다시이미지 build없이 코드가 반영 될 수 있게 volume을 사용한다.
    volumes:
      - /app/node_modules
      - ./frontend:/app
    stdin_open: true

  nginx:
    #재시작 정책
    #no: 어떠한 상황에서도 재시작을 하지 않습니다
    #always: 항상 재시작
    #on-failure: 에러코드와 함께 컨테이너가 멈추었을 때만 재시작 
    #unless-stopped 개발자가 임의로 멈추려고 할때 빼고는 항상 재시작
    restart: always
    build:
      dockerfile: Dockerfile
      context: ./nginx
    ports:
      - "3000:80"

  backend:
    build: 
      dockerfile: Dockerfile.dev
      context: ./backend
    #container_name: app_backend
    volumes:
      - /app/node_modules
      - ./backend:/app

  # mysql:
  #   build: ./mysql
  #   restart: unless-stopped
  #   container_name: app_mysql
  #   ports:
  #     - "3307:3307"
  #   volumes:
  #     - ./mysql/mysql_data:/var/lib/mysql
  #     - ./mysql/sqls/:/docker-entrypoint-initdb.d/
  #   environment:
  #     MYSQL_USER: root
  #     MYSQL_ROOT_PASSWORD: root
  #     MYSQL_DATABASE: myapp
  #     MYSQL_TCP_PORT: 3307
  #mysql의 root 비밀번호와 db를 설정해준다.
    

      

 

또한 주석 처리했던 backend/server.js의 주석을 해제해 준다..

 

backend/server.js

const express = require("express");
const db = require("./db");

const app = express();

app.use(express.json());

// 테이블 생성하기
db.pool.query(`CREATE TABLE lists (
    id INTEGER AUTO_INCREMENT,
    value TEXT,
    PRIMARY KEY (id)
)`, (err, results, fields) => {
    console.log('results', results);
})
app.get("/api", (req, res, next) =>{
  return res.json({hello:"hello"});
})
app.get("/api/values", (req, res, next) => {
  db.pool.query("SELECT *FROM lists;", (err, results, fields) => {
    if (err) return res.status(500).send(err);
    else return res.json(results);
  });
});

app.post("/api/value", (req, res, next) => {
  db.pool.query(
    `INSERT INTO lists (value) VALUES("${req.body.value}");`,
    (err, results, fields) => {
      if (err) return res.status(500).send(err);
      else return res.json({ success: true, value: req.body.value });
    }
  );
});

app.listen(5000, () => {
  console.log("this server listening on 5000");
});

 

 

배포를 위한 준비 - Github에 올리기 

 

먼저 git repository를 생성해준다.

 

 

그리고 해당 저장소와 로컬저장소를 연결시켜준다.

git init
git add .
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/아이디/저장소
git push -u origin main

 

 

 

 

 

 

이제 Travis CI로 이동해준다

 

travis CI가 push를 인식 -> 테스트 코드 실행 -> 성공하면 운영환경의 이미지 build -> 빌드된 이미지를 ->dockerhub에 보낸다

-> AWS EB에 dockerhub에 이미지를 보냈다고 알림 -> AWS EB에서 DockerHub에 있는 이미지를 가져온 후 배포 

 

 

 

 

Travis CI

github에서 진행되는 오픈소스 프로젝트를 위한 지속적인 통합(continuous Integration) 서비스

github repository에 있는 프로젝트를 특정 이벤트에 따라 자동으로 테스트, 빌드하거나 배포할 수 있다.

private repository는 유료로 일정금액을 지불하고 사용 할 수 있다.

 

 

travis-ci.org/

 

Travis CI - Test and Deploy Your Code with Confidence

 

travis-ci.org

 

 

 

 

settings -> repository에 가서

 

방금 올린 repository를 활성화 해준다. 

이를 활성화 하면

push가 일어날 때마다 travis CI가 이를 파악해서 테스트및 여러가지 활동을 가능케 한다.

 

없으면 sync account 버튼을 누른후 다시 검색한다.

 

이제 travis.yml 파일을 작성해준다. 

 

 

language: generic

sudo: required

services:
  - docker

before_install:
  - docker build -t loy124/react-test-app -f ./frontend/Dockerfile.dev ./frontend

script:
  - docker run -e CI=true loy124/react-test-app npm run test

after_success:
  #각 이미지 빌드 
  - docker build -t loy124/docker-frontend ./frontend
  - docker build -t loy124/docker-backend ./backend
  - docker build -t loy124/docker-nginx ./nginx
  #도커 허브 로그인
  #아이디는 travis CI 홈페이지에 미리 넣어준다.
  - echo "$DOCKER_HUB_PASSWORD" | docker login -u "$DOCKER_HUB_ID" --password-stdin
  #빌드된 이미지들을 도커 허브에 push
  - docker push loy124/docker-frontend
  - docker push loy124/docker-backend
  - docker push loy124/docker-nginx

 

Docker ID와 PASSWORD는 travis에서 설정해준다.

 

 

more options -> settings 

 

 

Enviroment Variables에 docker hub의 아이디와 비밀번호를 넣어준다.

 

 

환경변수까지 설정해줬으면 

 

남은 작업이 몇가지 있는데 

첫번째는 

 

 

 

frontend파트에 .git으로 자동으로 추가된 부분이 있다. 

해당 .git폴더를 제거해준다. 

git rm --cached . -rf

상위 docker-fullstack-app에서 git rm --cached . -rf를 실행해서 frontend폴더를 다시 인식하게 끔 캐시를 지워준다.

 

 

완료되었다면

 

git add .
git commit -m "travis yml added"
git push

push를 통해 원격 저장소에 업로드해준다. 

 

 

 

업로드 후 travis에 방문하면 travis 단에서 test를 진행한다.

 

 

테스트가 완료되면 build및 push 또한 거친다.

 

 

위와 같이 docker build가 되어 업로드에 성공하였다.

 

 

Docker Hub - AWS(Elastic Beanstalk) 연동하기

Dockerfile이 여러개인 경우 어떤 Dockerfile이 어떤 파일을 먼저 실행하고 어떤 행동을 취해 자동으로 프로세스를 정할 수 없기 때문에 임의로 설정을 해줘야하는 이에 따른 Elastic Beanstalk의 고유 JSON 파일이 Dockerrun.aws.jsn이다

해당 파일은 멀티컨테이너 Docker 환경에서 사용 할 수있다.

각 컨테이너 인스턴스에 배포할 컨테이너및 탑재할 컨테이너의 호스트 인스턴스에서 생성할 데이터 볼륨을 설명한다.

docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/create_deploy_docker_v2config.html

 

멀티컨테이너 Docker 구성 - AWS Elastic Beanstalk

멀티컨테이너 Docker 구성 Dockerrun.aws.json 파일은 Docker 컨테이너 세트를 Elastic Beanstalk 애플리케이션으로 배포하는 방법을 설명하는 Elastic Beanstalk 고유의 JSON 파일입니다. Dockerrun.aws.json 파일을 멀티

docs.aws.amazon.com

 

 

Dockerrun.aws.json

 

 

{
  "AWSEBDockerrunVersion": 2,
  "containerDefinitions": [
    {
      "name": "frontend",
      "image": "loy124/docker-frontend",
      "hostname": "frontend",
      "essential": false,
      "memory": 128
    },
    {
      "name": "backend",
      "image": "loy124/docker-backend",
      "hostname": "backend",
      "essential": false,
      "memory": 128
    },
    {
      "name": "nginx",
      "image": "loy124/docker-nginx",
      "hostname": "nginx",
      "essential": true,
      "portMappings": [
          {
              "hostPort": 80,
              "containerPort": 80
          }
      ],
      "links":["frontend", "backend"],
      "memory": 128
    }
  ]
}

 

 

name: 컨테이너의 이름

image: 온라인 Docker repository의 이름

hostname: 해당 이름을 이용해서 도커 컴포즈를 이용해 새성된 다른 컨테이너에 접근가능

essential: 컨테이너가 실패할 경우 작업을 중지해야하면 true 

memory: 컨테이너용으로 예약할 컨테이너 인스턴스에 있는 메모리양

portMappings: 컨테이너에 있는 네트워크 지점을 호스트에 있는 지점에 매핑

links: 연결할 컨테이너의 목록(nginx -> frontend, nginx -> backend)

 

 

 

설정을 완료했으니 이제 AWS에 접속해서 ElasticBeanStalk 환경을생성해준다. 

ap-northeast-2.console.aws.amazon.com/elasticbeanstalk/home?region=ap-northeast-2

 

https://ap-northeast-2.console.aws.amazon.com/elasticbeanstalk/home?region=ap-northeast-2

 

ap-northeast-2.console.aws.amazon.com

Elastic Beanstalk(EB)

apache, nginx와 같은 서버에서 java,net,node.js python, ruby, go 및 docker와 함께 개발된 웹 응용 프로그램을 배포및 확장하기 쉬운 서비스로써 환경을 구성및 관리해준다.

 

 

 

새환경 생성 을 눌러준다.

 

웹 서버 환경 선택

 

 

 

위와같이 설정하고 생성해준다.

 

완료된 모습 

 

AWS RDS 생성하기 

AWS RDS를 위해 이제 docker-compose부분및 backend의 db.js부분을 수정해준다.

 

docker-compose부분에서 AWSRDS를 위해 docker를 사용하지 않기 때문에 mysql파트를 주석처리하였다.

 

docker-compose.yml

version: "3"
services: 
  frontend:
    build:
      dockerfile: Dockerfile.dev
      context: ./frontend
    #코드 수정후 다시이미지 build없이 코드가 반영 될 수 있게 volume을 사용한다.
    volumes:
      - /app/node_modules
      - ./frontend:/app
    stdin_open: true

  nginx:
    #재시작 정책
    #no: 어떠한 상황에서도 재시작을 하지 않습니다
    #always: 항상 재시작
    #on-failure: 에러코드와 함께 컨테이너가 멈추었을 때만 재시작 
    #unless-stopped 개발자가 임의로 멈추려고 할때 빼고는 항상 재시작
    restart: always
    build:
      dockerfile: Dockerfile
      context: ./nginx
    ports:
      - "3000:80"

  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: root1234
       MYSQL_DATABASE: myapp
       MYSQL_PORT: 3306
  

  # mysql:
  #   build: ./mysql
  #   restart: unless-stopped
  #   container_name: app_mysql
  #   ports:
  #     - "3307:3307"
  #   volumes:
  #     - ./mysql/mysql_data:/var/lib/mysql
  #     - ./mysql/sqls/:/docker-entrypoint-initdb.d/
  #   environment:
  #     MYSQL_USER: root
  #     MYSQL_ROOT_PASSWORD: root
  #     MYSQL_DATABASE: myapp
  #     MYSQL_TCP_PORT: 3307
  #mysql의 root 비밀번호와 db를 설정해준다.
    

      

 

 

backend/ds.js

docker-compose backend의 enviroment로 부터 자동적으로 환경변수를 가져오게 변경해준다. 

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;

 

 

 

AWS RDS 만들기 

AWS RDS

아마존 관계형 데이터베이스 서비스 또는 아마존 RDS는 아마존 웹 서비스가 서비스하는 분산 관계형 데이터베이스이다. 애플리케이션 내에서 관계형 데이터베이스의 설정, 운영, 스케일링을 단순케 하도록 설계된 클라우드 내에서 동작하는 웹 서비스

 

 

 

 

 

 

데이터베이스 생성 

 

 

 

 mysql 선택 

 

 

root와 root1234로 지정해주었다. 

 

 

여기까지 진행하면 RDS 생성이 완료된다. 

 

 

 

이제 AWS의 RDS(관계형 데이터베이스) 를 설정하기 위해 MYSQL을 어플리케이션과 연결시켜줘야한다.

이를 위해 VPC와 Security Group을 설정해줘야한다.(EC2와 AWS RDS 연결)

 

 

Amazon Virtual Private Cloud(VPC)

VPC를 사용하면 VPC별로 네트워크를 구성 할 수 있고 각각의 VPC에 따라 다르게 네트워크 설정을 줄 수 있다.

각각의 VPC는 완전히 독립된 네트워크 처럼 작동한다. 

EB나 EC2등 환경을 생성 하면 기본적으로 default VPC가 적용되서 들어간다. 

 

 

EC2 인스턴스 접속해보면 VPC ID가 나와있다.

 

또한 Security Group 또한 설정해줘야한다.

 

Inbound

외부에서 EC2 인스턴스나 EB인스턴스등으로 요청을 보내는 트래픽, HTTP, HTTPS, SSH등

 

Outbound

EC2인스턴스나 EB인스턴스에서 외부로 나가는 트래픽 , 파일다운로드나 inbound로 들어온 트래픽 처리 응답등

 

 

 

Security Group 생성하기 

 

VPC -> 보안그룹으로 이동한다

 

 

 

보안 그룹 생성을 눌러준다 

 

 

 

 

 

 

보안그룹을 생성 한 후

인바운드 규칙을 편집해준다.

 

 

 

 

 

 

 

 

방금 만든 DockerSecurityGroup을 선택해서 지정해준다.

 

여기까지 SecurityGroup을 설정하였다면 

이제 

AWS RDS로 이동해서 보안그룹을 지정해줘야한다.

 

수정 버튼을 눌러서 보안 그룹을 추가해준다. 

보안 그룹에 DockerSecurityGroup 추가 

 

 

수정한 후 계속을 눌러준다

 

즉시 적용을 눌러주고 수정을 해준다. 

 

 

 

이제 EB Beanstalk부분에도 보안그룹을 추가해줘야한다.

 

EB -> Docker-fullstack-app으로 이동 -> 구성-> 인스턴스 클릭  클릭 

 

 

 

 

 

DockerSecurityGroup 추가후 저장(경고 무시)

 

 

여기까지 진행하면 보안 그룹설정은 마무리 된다.

 

하지만 ElasticBeanStalk 안에 있는 컨테이너들이 아직 Mysql 인스턴스와 소통할때 환경변수 부분을 인식하지 못합니다

따라서 해당 ElasticBeanStalk에 환경변수를 설정해줘야한다. 

 

먼저 이를 위해 AWS RDS DB에 방문해서 

 

엔드 포인트 주소를 가져온다.(복사)

 

그리고 나서 

 

Elastic Beanstalk -> 구성 -> 소프트웨어 편집 클릭 

 

 

환경속성 란의 부분과

 

docker-compose 부분을 일치화 시켜줘야하는데

HOST의 주소는 RDS의 엔드포인트로 지정해준다.

그후 적용을 눌러준다. 

 

 

이제 배포부분 설정을 위해 .travis.yml을 추가해준다.

 

language: generic

sudo: required

services:
  - docker

before_install:
  - docker build -t loy124/react-test-app -f ./frontend/Dockerfile.dev ./frontend

script:
  - docker run -e CI=true loy124/react-test-app npm run test

after_success:
  #각 이미지 빌드 
  - docker build -t loy124/docker-frontend ./frontend
  - docker build -t loy124/docker-backend ./backend
  - docker build -t loy124/docker-nginx ./nginx
  #도커 허브 로그인
  #아이디는 travis CI 홈페이지에 미리 넣어준다.
  - echo "$DOCKER_HUB_PASSWORD" | docker login -u "$DOCKER_HUB_ID" --password-stdin
  #빌드된 이미지들을 도커 허브에 push 
  - docker push loy124/docker-frontend
  - docker push loy124/docker-backend
  - docker push loy124/docker-nginx

deploy:
  #외부 서비스 표시(s3, elesticbeanstalk, firebase 등등)
  provider: elasticbeanstalk
  #현재 사용하고 있는 AWS의 서비스가 위치하고있는 물리 장소
  region: "ap-northeast-2"
  #생성된 어플리케이션의 이름
  app: "docker-fullstack-app"
  #elasticbeanstalk을 위한 s3 버켓이름
  env: "DockerFullstackApp-env"
  bucket_name: elasticbeanstalk-ap-northeast-2-770628485357
  bucket_path: "docker-fullstack-app"
  #특정 branch에만 해당 aws서버에 올릴 수 있게 설정해두었다.
  on:
    branch: main
  # iam 계정으로 부터 생성해서 travis ci에 저장해둔 key
  access_key_id: $AWS_ACCESS_KEY
  secret_access_key: $AWS_SECRET_ACCESS_KEY


Elastic Beanstalk
bucket_name

 

이제 travis CI와 AWS가 실질적으로 소통을 할수 있게 인증해주는 작업 이 필요하다.

 

API를 발급받아야 하는데 

이를 위해 IAM 계정을 먼저 생성하고 진행한다

기존 AWS root login을 진행할 경우 보안상 좋지 않기 때문에 IAM 계정을 생성한다.

 

IAM 계정은 root사용자가 부여한 권한만 사용할 수 있다.

 

 

 

IAM -> 사용자 -> 사용자 추가를 눌러준다. 

 

 

 

 

사용자 이름및 유형을 선택해주고 

 

AWSElasticBeanstalkFullAccess 권한을 준다. 

 

사용자를 만들어준다.

 

해당 엑세스 키와 비밀 액세스 키를 잘 보관한다. 

 

 

이제 해당 액세스 키와 비밀 액세스 키를 travis 웹사이트에 저장해준다.

 

 

 

여기까지 진행하면 마무리가 되고 이제 직접 배포하는일만 남았다.

 

 

git add .
git commit -m "travis CI deploy Added"
git push

 

travis 단에서 정상적으로 배포가 된 것을 확인하면

 

 

 

aws beanstalk에 접속해서 사이트에 접속해본다. 

 

 

 

성공적으로 프로젝트 배포가 완료되었다.

 

 

 

 

 

 

 

 

 

위 글은 

www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%A9%B0-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EB%8F%84%EC%BB%A4-ci/dashboard

해당 강의를 듣고 정리하는 내용입니다.

 

반응형