도커와 CI 환경 - 7

지원·2024년 3월 31일
0

Docker

목록 보기
7/7

설명

  • 이전에 했었던 부분은 애플리케이션을 위한 전체 소스코드를 작성하고 각각에 맞는 Dockerfile 을 작성했으며 그 각각의 컨테이너를 연결시켜주고 간단하게 한 번에 실행시킬 수 있는 Docker compose 를 작성했다.
  • 이번에는 소스코드가 에러가 없는지 테스트를 한 후 테스트에서 성공을 하면 AWS 를 통해서 배포를 하는 것을 해볼 예정이다.

데이터베이스를 운영환경에서는 AWS RDS 를 사용해야하기 때문에 이전에 작성했던 mysql 부분을 수정을 먼저 해보자.

도커 환경의 MySQL 부분 정리

  • mysql 이 도커 안에서 돌아가는게 아닌 AWS 에서 돌아가고 있는 것을 우리의 어플리케이션에 연결만 해줄것이니 mysql 을 어플리케이션에 연결해주는 부분 빼고 다 지워준다.
  • 그래서 docker-compose.yml 에서 mysql 부분을 모두 주석 처리만 해주면 된다.

Github 에 소스 코드 올리기

  • github 에서 repository 생성
  • git init -> git add -> git commit -> git remote add origin -> git push origin main

Travis CI

  • Github main 브랜치에 새로 업데이트된 소스가 올라왔다면 그 소스를 Travis CI 에서 가져와야 한다.

Travis CI 에서 하는 일들

  1. Github 에 코드 Push
  2. Travis CI 가 자동으로 코드를 가져온다.
  3. 가져온 코드로 "테스트" 코드를 실행
  4. 성공하면 운영 환경의 이미지를 빌드
  5. 빌드된 이미지를 Docker Hub 로 전송
  • Docker Hub 에서는 유명한 이미지를 다운로드 받을 수 있고, 자신이 만든 이미지도 업로드 할 수 있다.
  • Docker Hub 에 빌드된 이미지를 보내고 AWS 에서 그 이미지를 가져간다.
  • 따라서 ElasticBeanStalk 에서 다시 이미지를 빌드하지 않아도 된다.
  1. AWS EB 에 DockerHub 에 이미지를 보냈다고 알린다.
  2. AWS EB 에서 DockerHub 에 있는 이미지를 가져온 후 배포

순서

  • Travis CI 사이트로 가서 Github 아이디로 로그인
  • Setting 페이지에서 위에서 올렸던 Repository 를 찾고 Setting 버튼 누른다.
  • 그렇게 되면 Travis CI 에게 Github 저장소의 소스가 변경될 떄 마다 소스를 가져와서 테스트하고 배포하라고 알려준다.

.travis.yml 파일 작성

  1. 파일생성 (.travis.yml)
  2. 테스트를 수행하기 위한 준비
  • 앱을 도커 환경에서 실행하고 있기 때문에 Travis CI 에게 도커 환경으로 만들라고 선언
  • 구성된 도커 환경에서 Dockerfile.dev 를 이용해 도커 이미지 생성
  1. 테스트 수행
  • 생성된 테스트 이미지를 이용해 테스트 수행
  1. 모든 프로젝트의 운영 버전 이미지 빌드
  • 테스트에 성공하면 각 프로젝트의 운영 버전 이미지를 빌드하도록 설정
  1. 빌드된 이미지를 도커 허브로 푸시
  • 빌드된 파일을 도커 허브에 보내기 위해 도커 허브 로그인
  • 빌드된 이미지 도커 허브로 푸시
  1. 배포
  • AWS ElasticBeanStalk 이 업데이트된 빌드 이미지를 가져와서 배포할 수 있게 설정
# .travis.yml

# 언어 (플랫폼) 선택
language: generic

# 관리자 권한 갖기
sudo: required

# 도커 환경 구성
services:
  - docker

# 스크립트를 실행할 수 있는 환경 구성
before_install:
  # Dockerfile.dev 명시 하기 위해 -f 옵션 사용
  - docker build -t supportkim/react-test-app -f ./frontend/Dockerfile.dev ./frontend

# 실행할 스크립트 (테스트 실행)
script:
  - docker run -e CI=true supportkim/react-test-app npm run test

# 테스트 성공 후 할일 명시
after_success:
  # 각각의 이미지 빌드
  - docker build -t supportkim/docker-frontend ./frontend
  - docker build -t supportkim/docker-backend ./backend
  - docker build -t supportkim/docker-nginx ./nginx

  # 도커 허브 로그인
  - echo "$DOCKER_HUB_PASSWORD" | docker login -u "$DOCKER_HUB_ID" --password-stdin

  # 빌드 된 이미지들을 도커 허브에 PUSH
  - docker push supportkim/docker-frontend
  - docker push supportkim/docker-backend
  - docker push supportkim/docker-nginx
  • travis.yml파일에 아이디와 비밀번호를 넣으면 노출 위험이 있기 때문에 도커 허브 아이디와 비밀번호를 Travis CI 홈페이지에 미리 넣어줘야 한다.
  • Travis CI 에서 Repository 를 찾고 More options -> Settings 에서 환경 변수를 만들어주면 된다. (DOCKER_HUB_ID , DOCKER_HUB_PASSWORD)
  • 이렇게 만들면 Travis CI 가 Script 에서 이 변수를 읽을 떄 자동으로 해당하는 값을 가져가서 로그인 할 수 있다.

정리

  • .travis.yml 에서는 도커 환경으로 선언하고 스크립트를 실행하기 이전에 Dockerfile.dev 로 도커 이미지를 만든다.
  • 그 도커 이미지로 테스트를 실행하고 이것이 성공되면 Dockerfile 로 각각의 이미지를 빌드하고 그 이미지들을 도커 허브에 넣는 로직을 수행한다.

Dockerrun.aws.json 이란?

  • 이전에는 Dockerfile 이 하나였기 때문에 Dockerrun.aws.json 을 사용하지 않아도 됐다.
  • 하지만 이번에는 도커 파일이 여러 개를 가지기 떄문에 Dockerrun.aws.json 이 필요하다.
  • 여러가지 도커파일이 있을땐 ElasticBeanStalk 이 어떤 파일을 먼저 실행하고 어떻게 행동을 취해야 하는지 자동으로 프로세스를 해나갈 수 없기 떄문에 우리가 임의로 설정을 해줘야 한다.
  • 그걸 설정해주는 파일이 바로 Dockerrun.aws.json 이다.
  • 즉 여러 개의 도커 파일이 있을 때 어떻게 수행해야할지 알려주는 문서라고 생각하면 된다.

EalsticBeanStalk 은 사실 어떻게 컨테이너를 실행해야하는지 모른다.

  • 그래서 EB 안에 있는 ECS (Elastic Container Service) 안에 Task 에다가 어떻게 컨테이너를 실행할지 정의 해야하는데 이를 작업 정의 (Trask Definition) 이라고 한다.
  • 또한 작업 정의를 등록할 때는 컨테이너 정의(Container Definition) 을 명시해야 한다.
  • 컨테이너 정의는 Dockerrun.aws.json 에 명시한다.

정리하면 작업 정의를 등록하려면 Container Definitoin 을 명시해줘야 하고 Container Definition 은 dockerrun.aws.json 에 명시해주며 도커 Daemon 으로 전해진다.

Dockerrun.aws.json 파일 작성

  1. Dockerrun.aws.json 파일 생성
  2. Container Definitions 작성
// Dockerrun.aws.json
{
  // Dockerrun 버전 지정
  "AWSEBDockerrunVersion" : 2,
  // 이 안에서 컨테이너들을 정의
  "containerDefinitions" : [
    {
      // 컨테이너의 이름
      "name" : "frontend",
      // Docker 컨테이너를 구축할 Docker 이미지 이름
      "image" : "supportkim/docker-frontend",
      // 호스트 이름으로, 이 이름을 이용해서 Docker Compose 를 통해 생성된 다른 컨테이너에서 접근이 가능
      "hostname" : "frontend",
      // 컨테이너가 실패할 경우 작업을 중지해야 하면 true , 그렇지 않으면 false
      "essential" : false,
      // 컨테이너용으로 예약할 컨테이너 인스턴스에 있는 메모리 양
      "memory" : 128
    } ,
    {
      "name" : "backend",
      "image" : "supportkim/docker-backend",
      "hostname" : "backend",
      "essential" : false,
      "memory" : 128
    } ,
    {
      "name" : "nginx" ,
      "image" : "supportkim/docker-nginx",
      "hostname" : "nginx",
      "essential" : true,
      // 컨테이너에 있는 네트워크 지점을 호스트에 있는 지점에 매핑
      "portMappings" : [
        {
          "hostPort" : 80,
          "containerPort" : 80
        }
      ] ,
      // 연결할 컨테이너의 목록으로, 연결된 컨테이너는 서로를 검색하고 안전하게 통신할 수 있다.
      "links" : ["frontend" , "backend"],
      "memory" : 128
    }
  ]
}
  • 각 컨테이너들의 작업 정의를 해주면 된다.
  • nginx 는 매우 중요하기 때문에 essential 을 true 를 줬고, nginx 를 통해 각 서버로 가기 때문에 links 도 설정해준다.

다중 컨테이너 앱을 위한 Elastic BeanStalk 환경 생성

  • AWS ElasticBeanStalk 에 들어가서 Create Application 을 한다.
  • 적절한 애플리케이션 이름을 넣어주고 플랫폼은 Docker 를 지정하고 플랫폼 브랜치는 Multi-container 로 해주면 된다.

VPC(Virtual Private Cloud) 와 Security Group 설정

  • AWS 의 RDS 를 이용하여 MySQL 을 애플리케이션과 연결시켜야 하는데 그것을 하기 위해서 VPC 와 Security Group 을 설정해줘야 한다.

그렇다면 왜 VPC 와 Security Group 을 설정해줘야 할까?

  • ElasticBeanStalk -------(X)-------> RDS(MySQL)
  • AWS 에서 기본적으로 연결돼 있지 않아서 서비스간에 통신할 수 없기 떄문에 따로 설정해서 연결해야 한다.

VPC 란?

  • VPC 를 사용하면 AWS 클라우드에서 논리적으로 격리된 공간을 제공하여 고객이 정의하는 가상 네트워크에서 AWS 리소스를 시작할 수 있다.
  • 즉 내가 만든 EC2 인스턴스나 RDS , EB 에 나의 아이디에서만 접근이 가능하게 논리적으로 격리된 네트워크에서 생성이 되게 해주는 것이다.
  • 그렇기 때문에 다른 아이디로 접근하는 것은 물론 보는것도 불가능하게 된다.
  • ElasticBeanStalk 인스턴스나 RDS 를 생성하면 자동적으로 기본 VPC 가 할당이 되고 할당이 될때는 지역별로 다르게 할당이 된다.

Security Group (보안 그룹) 이란?

  • 보안 그룹에는 인바운드와 아웃 바운드라는게 존재한다.
  • 인바운드는 외부에서 EC2 인스턴스나 EB 인스턴스로 요청을 보내는 트래픽으로 HTTP , HTTPS , SSH 등이 있다.
  • 아웃 바운드는 EC2 인스턴스나 EB 인스턴스등에서 외부로 나가는 트래픽으로, 파일을 다운로드 하거나 인 바운드로 들어온 트래픽을 처리하여 응답하는 경우도 포함된다.

즉 Security Group 이 인바운드와 아웃바운드를 통제해서 트래픽을 열어줄 수 있고 닫아 줄 수도 있다.

그렇다면 어떻게 VPC 와 Security Group 을 이용해서 EB 인스턴스와 RDS 가 서로 통할 수 있게 만들 수 있을까?

  • 같은 VPC 안에 AWS 서비스 간에는 트래픽을 모두 허용할 수 있는 Security Group 을 만들어주면 된다.
  • 즉 EB 인스턴스와 RDS 가 존재하는 VPC 에 오는 트래픽은 모두 허용하는 보안 그룹을 만들면 된다.

MySQL 을 위한 AWS RDS 생성

  • AWS RDS 에서 데이터 베이스를 생성하고 엔진 옵션을 선택하고 USERNAME , PASSWORD 을 설정해준다.
  • 데이터베이스 옵션에서 초기 데이터베이스 이름도 설정할 수 있고, 자동 백업 활성화도 체크해준다.

Security Group 생성 및 적용

  • 보안 그룹 생성할 때 인바운드 규칙은 MySQL(3306) 만 추가해주면 된다.
  • MySQL 과 소통을 해야하기 때문에 MySQL 이 실행되고 있는 Port 인 3306 을 적어주면 된다.

RDS 에 생성한 보안 그룹 적용

  • AWS RDS 에 들어가서 생성한 RDS 에서 위에서 만든 보안 그룹을 추가해주면 된다.

EB 에 생성한 보안 그룹 적용

  • AWS EB 에 들어가고 만들었던 환경 이름을 클릭한 후 구성에 들어간다.
  • 인스턴스 편집을 들어가고 위에서 생성한 보안 그룹을 추가하고 적용해주면 된다.

EB 와 RDS 소통을 위한 환경 변수 설정

  • 보안 그룹까지 다 설정했지만, 아직은 ElasticBeanStalk 안에 있는 컨테이너들이 MySQL 인스턴스와 소통할 때 환경변수 부분을 인식하지 못한다.
  • 그래서 AWS ElasticBeanStalk 에 환경변수를 설정하므로써 그 부분의 문제를 해결해보자.
  • AWS ElasticBeanStalk 에 들어가고 구성에서 소프트웨어 편집을 눌러준다.
  • 환경 속성에 MYSQL_HOST (RDS EndPoint) , MYSQL_USER , MYSQL_PASSWORD , MYSQL_DATABASE , MYSQL_PORT 와 같은 정보들을 넣어준다.
  • 이렇게 설정하면 EB 와 RDS 가 소통할 때 해당 환경변수를 참고하면서 소통을 할 수 있다.

travis.yml 파일 작성 (배포)

  • 현재 각각의 필요한 이미지들을 빌드한 후 도커 허브까지 넣어줬다.
  • 이제는 AWS 에서 배포를 위해 필요한 설정들을 travis.yml 파일에 작성해주면 된다.
# .travis.yml 에 추가
deploy:
  # 외부 서비스 표시 (s3 , firebase , eb 등)
  provider: elasticbeanstalk
  # 현재 사용하고 있는 AWS의 서비스가 위치하고 있는 물리적인 위치
  region: "ap-northeast-2"
  # 생성된 어플리케이션의 이름
  app: "docker-fullstack-app"
  # env 이름
  env: "DockerFullstackApp-env"
  # 해당 EB 를 위한 S3 버켓 이름
  bucket_name: "버킷 이름"
  # 어플리케이션의 이름과 동일
  bucket_path: "app 이름과 동일"
  on:
  # 어떤 브랜치에 Push 를 할 떄 AWS 에 배포를 할 것인지 설정
    branch: main
  • 대부분의 설정이 끝났지만 이렇게 아무런 인증 없이는 Travis CI 에서 마음대로 AWS 과 소통할 수 없다.
  • 이제는 Travis CI 가 AWS 에 접근할 수 있게 해주는 방법을 알아보자.

Travis CI 의 AWS 접근을 위한 API key 생성

  • 현재까지 Travis CI 에서 AWS 에 어떤 파일을 전해줄 것이며, AWS 에서 어떤 서비스를 이용할 것이며, 부수적인 설정들을 넣어줬다.
  • 하지만 Travis CI 와 AWS 가 실질적으로 소통을 할 수 있게 인증하는 부분을 설정해주진 않았다.

인증을 위해서는 API Key 가 필요하다.

  • API Key 를 받기 위해서는 IAM USER 를 생성해야 한다.
  • AWS IAM 에서 사용자 추가를 한다.
  • 사용자 세부 설정 정보에서 적절한 이름을 넣어주고 프로그래밍 방식 엑세스를 선택한다.
  • 현재 EB 를 사용하기 때문에 기존 정책 직접 연결에서 AWSElasticBeanstalkFullAccess 를 선택한다.
  • 그렇게 만든 USER 에서 API Key 를 만들면 된다.
  • 해당 API Key 는 .travis.yml 에 적어 주면 노출이 되기 떄문에 다른 곳에 적고 그것을 가져와야 한다.
  • 그래서 Travis 에서 More options -> Settings 에 AWS_ACCESS_KEY , AWS_SECRET_ACCESS_KEY 추가 하고 .travis.yml 파일에 아래 내용을 추가해주면 된다.
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_ACCESS_KEY

main 에 push 하면 travis CI 에서 테스트를 진행하고 AWS EB 로 전달되서 업데이트를 하고 나면 정상적으로 실행이 된다.

Travis CI 에서 Github Action 으로 교체

  1. .travis.yml 을 삭제 후 github action 의 deploy.yaml 로 교체
  • .github/workflows/deploy.yaml
# deploy.yaml
name: Deploy FullStackApp

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      # Travis CI 와 같이 도커에 로그인
      - run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
      # before_install
      - run: docker build -t supportkim/react-test-app -f ./frontend/Dockerfile.dev ./frontend
      # 테스트 하는 코드 (script)
      - run: docker run -e CI=true supportkim/react-test-app npm test

      # after_success
      - run: docker build -t supportkim/docker-frontend ./frontend
      - run: docker build -t supportkim/docker-nginx ./nginx
      - run: docker build -t supportkim/docker-backend ./backend

      - run: docker push supportkim/docker-frontend
      - run: docker push supportkim/docker-nginx
      - run: docker push supportkim/docker-backend

      # ElasticBeanStalk 에 전달
      - name: Generate deployment package
        run: zip -r deploy.zip . -x '*.git*'

      - name: Deploy to EB
        uses: einaregilsson/beanstalk-deploy@v18
        with:
          aws_access_key: ${{ secrets.AWS_ACCESS_KEY }}
          aws_secret_key: ${{ secrets.AWS_SECRET_KEY }}
          # 바꿔줘야 하는 부분 1
          application_name: fullstack-docker-app
          # 바꿔줘야 하는 부분 2
          environment_name: Fullstack-docker-app-env
          # 바꿔줘야 하는 부분 3
          existing_bucket_name: elasticbeanstalk-ap-northeast-2-637423586273
          region: ap-northeast-2
          version_label: ${{ github.sha }}
          deployment_package: deploy.zip
# docker-compose.yml
version: "3"
services:
  frontend:
    image: supportkim/docker-frontend
    volumes:
      - /app/node_modules
      - ./frontend:/app
    stdin_open: true
    mem_limit: 128m

  nginx: 
    restart: always
    image: supportkim/docker-nginx
    ports: 
      - "80:80"

  backend:
    image: supportkim/docker-backend
    container_name: app_backend
    volumes:
      - /app/node_modules
      - ./backend:/app
    mem_limit: 128m
    environment: 
      MYSQL_HOST: $MYSQL_HOST 
      MYSQL_USER: $MYSQL_USER 
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
      MYSQL_DATABASE: $MYSQL_DATABASE
      MYSQL_PORT: $MYSQL_PORT   
  1. 역할 생성
  • 역할 생성에 들어가서 AWSElasticBeanstalkMulticontainerDocker , AWSElasticBeanstalkWebTier , AWSElasticBeanstalkWorkerTier 3개 추가
  1. ElasticBeanStalk 만들기
  • ElasticBeanStalk 에서 애플리케이션 생성
  • 적절한 이름 생성 후 서비스 액세스에서 새 서비스 역할 생성 및 사용을 누르고 EC2 인스턴스 프로파일에서 2번에서 생성한 역할을 지정해준다.
  1. IAM 유저 생성
  • AdministratorAccess-AWSElasticBeanstalk 정책을 가지는 유저 생성
  • 생성한 후 보안 증명에 들어가서 Key 를 발급 후 보관
  1. GitHub Repository 생성
  • Github 에 저장소를 만들고 해당 코드들을 다 PUSH 해준다.
  • Repository 에서 Settings -> Secrets and variables -> Actions 로 가서 값을 하나씩 넣어주면 된다.
  • AWS_ACCESS_KEY , AWS_SECRET_KEY , DOCKER_USERNAME , DOCKER_PASSWORD
  1. RDS 생성

  2. 보안 그룹 생성

  • 인바운드 규칙에 3306 만 추가
  • EB , RDS 에 해당 보안 그룹을 적용시키면 된다.
  • EB 는 구성에서 인스턴스 트래픽 및 크기 조정에서 보안그룹을 정해주면 된다.
  1. 환경변수 설정
  • docker-compose.yml 을 이용해서 EB 에서 도커 컨테이너를 실행한다.
  • 이때 docker-compose.yml 안에 있는 DB 관련 환경변수들을 EB 에 넣어줘야 한다.
  • 구성 -> 업데이트 , 모니터링 및 로깅 편집 -> 환경속성에서 환경변수 추가
  • MYSQL_HOST , MYSQL_USER , MYSQL_ROOT_PASSWORD , MYSQL_DATABASE , MYSQL_PORT 값들을 추가 해줬다.

이렇게 GitAcation 으로 CI/CD 파이프라인을 구축할 수 있다.

참고자료

profile
덕업일치

0개의 댓글