땅굴파는이야기-Docker로 CI/CD 구축하기

정 승 연·2023년 4월 7일
0

땅굴파는 이야기

목록 보기
1/5

Docker로 CI/CD 구축하기


땅굴 증명

지난번 프로젝트 때 Github Actions 와 AWS Codedeploy를 이용한 CI/CD를 구축했었다.

그러던 어느날 Docker로 서버 배포를 한다는 이야기를 들었다.

그냥 지나가다가 Docker를 들어본 적이 있다. 돌고래 위에 올라간 컨테이너들로 기억하는데 해커톤 때 Docker로 서버 배포를 한다는 말을 듣고 귀가 쫑긋했다.

내가 알기로 Docker는 좋은거다. 좋은 거였다. 먼저 도커가 뭔지 알아봐야겠다.

돌고래 위 컨테이너

Virtual machine

가상화는 하나의 하드웨어를 여러개의 가상머신으로 분할해 효율적으로 사용할 수 있는 기술이다. 분할된 가상머신들은 각각 독립적인 환경에서 구동되며 기존 base 환경을 Host OS, 가상머신으로 분할된 각 환경을 Guest OS 라고 부른다.

우리가 가장 쉽게 접하는 Virtual box, Vmware 등으로 리눅스에 접근하는것이 그 예다.

마치 하드웨어가 여러개인 것처럼 하나의 서버를 여러명이 나눠쓸 수 있고 컴퓨터 한대에서 서로 다른 os를 동시에 사용할 수 있다.

Container

그와 달리, 컨테이너는 가상의 OS를 만드는 것이 아닌, base의 OS를 공유하며 필요한 프로세스만 격리하는 방식이다. 커널을 공유해 Host OS의 기능을 모두 사용할 수 있고 그렇기때문에 Host OS와 같은 OS를 구동해야한다.

격리시킬 애플리케이션과 그에 필요한 특정 라이브러리등 종속항목만 포함한 이미지로 격리한다.

Host OS를 공통으로 사용하기때문에 배포를 위해 생성되는 이미지의 용량이 작다. 운영체제가 아닌 프로세스이며, 실행속도 또한 빠르다. 이미지를 실행하면 프로세스, 즉 컨테이너가 된댜.

Docker

Container 기반의 가상화 플랫폼이다. 도커를 이용하면

이미지를 실행시켜 컨테이너로 만들거나,

생성된 컨테이너(프로세스)를 관리하거나,

컨테이너를 다시 이미지로 만드는 작업을 쉽게 할 수 있다.

특히 배포 과정에서 도커를 이용해 필요한 파일들만 예쁘게 모아서 이미지로 만들면 정말 지긋지긋한 종속성 이슈에서 벗어날 수 있다.

(매번 새로운 ec2 팔 때마다 sudo apt install 설치설치설치 .. 했는데 이제 살았다? 필요한 스펙 이미지를 잘 관리해야할듯하다!)

따라서 도커는

개발환경과 관계없이 동일한 어플리케이션을 올릴 수 있게 해준다.

AWS EC2에 Docker 띄우는 CI/CD

AWS EC2, Docker, Github Actions 사용

0. 프로젝트 파일에 Dockerfile 추가

FROM openjdk:11-jdk
ARG JAR_FILE=./build/libs/{PROJECT-NAME}-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

{PROJECT-NAME} 은 build한 jar 파일에서 찾아서 한다.

1. AWS EC2 생성

일련의 과정은 이 포스팅을 참고하길 바란다!

  • 보안그룹 인바운드 규칙 주의
  • 프리티어 과금 주의

원래 Ubuntu 로 만들었었는데, 이번에 처음으로 AWS Linux로 해보았다.

Amazon Linux2는 차세대 Amazon Linux 운영 체제로, 현대 애플리케이션 환경에 Linux 커뮤니티의 최신 기능과 장기적인 기능을 제공한다고 합니다.

라는 말에 AWS Linux로 해보았다.

2. EC2에 Docker 설치

생성된 EC2를 ssh를 통해 접속한다.

접속 후 Docker를 설치한다.

# yum으로 Docker 설치
sudo yum update -y
sudo yum install docker -y

# Docker 버전 확인
docker -v

# Docker 실행
sudo service docker start

# Docker는 자원을 사용하기 때문에 sudo가 필요하다. sudo 없이도 실행할 수 있도록 해줌
# 실행 후 우분투를 재가동 해야함
sudo usermod -a -G docker ec2-user

3. Github Secrets 추가

  • APPLICATION application.properties 파일 그대로 업로드
  • DOCKER_USERNAME dockerhub 계정 아이디
  • DOCKER_PASSWORD dockerhub 계정 비밀번호
  • EC2_SERVER_HOST AWS 인스턴스 퍼블릭 IP
  • PRIVATE_KEY 위아래 포함 해야함
    -----BEGIN RSA PRIVATE KEY-----
    keyaowiejfoiajw
    -----END RSA PRIVATE KEY-------

4. Github Actions에 gradle.yml 추가

Github Repository 에서 Actions → Java with Gradle 선택

# github repository actions 페이지에 나타날 이름
name: CI/CD using github actions & docker

# main 브랜치에 push가 되었을 때 실행
on:
  push:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  CI-CD:
    runs-on: ubuntu-latest
    steps:

      # JDK setting - github actions에서 사용할 JDK 설정 (프로젝트나 AWS의 java 버전과 달라도 무방)
      - uses: actions/checkout@v3
      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'

      # gradle caching - 빌드 시간 향상
      - name: Gradle Caching
        uses: actions/cache@v3
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      # 환경 yml 파일 생성 - application.properties
      - name: make application.properties
        if: 
          contains(github.ref, 'main')
        run: |
          mkdir ./src/main/resources # resources 폴더 생성
          cd ./src/main/resources # resources 폴더로 이동
          touch ./application.properties # application.yml 생성
          echo "${{ secrets.APPLICATION }}" > ./application.properties # github actions에서 설정한 값을 application.properties 파일에 쓰기
        shell: bash

      # gradle build
      - name: Build with Gradle
        run: ./gradlew build -x test

      # docker build & push to production
      - name: Docker build & push to prod
        if: contains(github.ref, 'main')
        run: |
          docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
          docker build -f Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/docker .
          docker push ${{ secrets.DOCKER_USERNAME }}/docker

      ## deploy to production
      - name: Deploy to prod
        uses: appleboy/ssh-action@master
        id: deploy-prod
        if: contains(github.ref, 'main')
        with:
          host: ${{ secrets.EC2_SERVER_HOST }} # EC2 퍼블릭 IPv4 DNS
          username: ec2-user
          key: ${{ secrets.PRIVATE_KEY }}
          envs: GITHUB_SHA
          script: |
            sudo docker ps
            sudo docker pull ${{ secrets.DOCKER_USERNAME }}/docker
            sudo docker run -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/docker
            sudo docker image prune -f

작성 시 주의사항

  1. application.properties 잘 작성하기
  2. Github Secret 작성
  3. run 포트번호 주의

Docker 명령어

# docker hub으로부터 image 다운
docker pull 

# image 목록 보기
docker images

# 컨테이너 생성 및 접속
docker run REPOSITORY

# 실행중인 컨테이너 목록 확인
docker ps

# 종료된 컨테이너 시작
docker start CONTAINER_ID

# -d: 컨테이너를 일반 프로세스가 아닌 데몬프로세스로 실행하여 프로세스가 끝나도 유지되도록 한다.
# -p: 호스트 컴퓨터에서 설정한 포트
docker run -d -p 8080:8080

# 사용중이 아닌 모든 이미지 삭제
docker image prune -f

5. Github Actions에서 ✅ 확인

6. 퍼블릭IP:8080 확인

             그럼 docker를 이용한 CI/CD 구축 완료!

7. 근데 안됐다? 확인해봐야 할 것들

  1. AWS EC2 인바운드 규칙

    인바운드 규칙은 다음을 열어두면 좋다. (사실 이렇게 많이 열어두면 안된다. 열어두면 좋다기보다 열어둬야 다 접근 가능하다?)

    HTTP80
    HTTPS443
    MYSQL3306
    사용자지정 TCP8080
    ssh22
  2. EC2 퍼블릭 여부

  3. 스프링 포트번호와 gradle.yml에서 명시한 포트번호

8. 근데 궁금한점

  1. docker로 rds까지 연결하는 방법은 없을까?
  2. 있더라도 그게 프리티어로 가능할까?
  3. docker로 실행했을 때의 성능과 그냥 noloop으로 실행했을때의 성능의 차이가 있을까?

to be continued ..

0개의 댓글