저번에 방학 동안 프로젝트를 했을 때 github action과 CodeDeploy를 사용하여 CI/CD를 구축했었습니다.
그때는 AWS를 사용해서 AWS에 제일 최적화한 것이 CodeDeploy이기 때문에 codeDeploy를 선택했었습니다.
이번에 혼자 해보는 프로젝트에서는 docker를 사용해 보려고 합니다.
Docker란?
- Docker는 컨테이너화된 애플리케이션을 만들고 실행하기 위한 오픈 소스 플랫폼입니다. 컨테이너는 애플리케이션과 해당 애플리케이션을 실행하는 데 필요한 모든 종속성(라이브러리, 환경 설정 등)을 포함하는 완전한 실행 환경입니다.
- Docker를 사용하면 애플리케이션을 컨테이너로 패키징 할 수 있으며, 이 컨테이너는 호스트 시스템에서 독립적으로 실행될 수 있습니다. 컨테이너는 가볍고 빠르며, 동일한 환경에서 일관성 있게 실행될 수 있습니다. 또한, Docker는 호스트 시스템의 운영 체제와 독립적으로 동작하므로, 다양한 운영 체제에서 동일한 컨테이너를 실행할 수 있습니다.
이미지와 컨테이너란?
- 이미지 (Image)
- Docker 이미지는 애플리케이션과 그 애플리케이션을 실행하는 데 필요한 모든 것들을 포함하는 패키지입니다.
- 이미지는 읽기 전용이며, 컨테이너를 생성하는 데 사용됩니다.
- 일반적으로 Docker 이미지는 여러 개의 레이어로 구성되며, 각 레이어는 파일 시스템의 변경 사항을 나타냅니다.
- Docker 이미지는 다른 이미지를 기반으로 만들 수 있으며, Dockerfile이라는 텍스트 파일에 명령어를 기록하여 이미지를 정의합니다.
- Dockerfile에는 기본 이미지, 애플리케이션의 종속성 설치, 환경 설정 등이 포함된다.
- Docker 이미지는 버전 관리가 가능하며, 버전 태그를 통해 특정 버전의 이미지를 지정할 수 있습니다.
- Docker 이미지는 Docker Hub와 같은 온라인 이미지 레지스트리에 저장되어 공유할 수 있으며, 개발자들은 필요한 이미지를 가져와 사용하거나, 직접 이미지를 빌드하여 공유할 수 있습니다.
- 컨테이너 (Container)
- Docker 컨테이너는 이미지의 인스턴스입니다.
- 컨테이너는 이미지를 기반으로 생성되며, 실행 중인 애플리케이션을 포함합니다.
- 컨테이너는 격리된 프로세스로, 호스트 시스템과 독립적으로 실행됩니다.
Docker 이미지는 애플리케이션과 그 실행에 필요한 모든 것을 포함하는 패키지이고, 컨테이너는 이미지의 인스턴스로, 격리된 환경에서 애플리케이션을 실행합니다. Docker를 사용하면 이미지와 컨테이너를 통해 애플리케이션을 쉽게 패키징, 배포 및 실행할 수 있습니다.
Docker와 CodeDeploy의 차이
Docker의 장점
- 일관성 : Docker는 컨테이너를 사용하여 환경 일관성을 제공하므로, 개발, 테스트, 프로덕션 환경에서 동일한 환경을 유지할 수 있습니다.
- 이식성 : Docker 컨테이너는 운영 체제와 독립적으로 실행될 수 있어, 다양한 환경에서 쉽게 이식할 수 있습니다.
- 속도와 확장성 : 가볍고 빠르며, 여러 단계와 작업을 병렬로 실행할 수 있어 배포 속도와 효율성을 높일 수 있습니다.
- 격리와 안정성 : 각 컨테이너는 격리되어 있으므로, 한 컨테이너의 문제가 다른 컨테이너에 영향을 주지 않고 안정성이 높아집니다.
- 확장성과 유연성 : 각각의 컨테이너로 구성 요소를 관리할 수 있어, 도구, 라이브러리, 데이터베이스 등을 독립적으로 관리하고 업데이트할 수 있습니다.
AWS CodeDeploy의 장점
- 서비스 제공 : AWS CodeDeploy는 클라우드 기반의 서비스로 제공되어, 손쉽게 사용할 수 있습니다.
- 확장성 : AWS CodeDeploy는 AWS의 다른 서비스와 통합되어 확장성이 뛰어나며, 다양한 배포 옵션을 제공합니다.
- 배포 전략 : CodeDeploy는 다양한 배포 전략을 지원하여 롤백, 롤아웃, 블루-그린 배포 등을 쉽게 구현할 수 있습니다.
- 모니터링 : CodeDeploy는 배포 과정을 모니터링하고, 오류를 자동으로 처리하고 복구할 수 있는 기능을 제공합니다.
- 다양한 플랫폼 지원 : CodeDeploy는 다양한 플랫폼과 언어를 지원하여 다양한 애플리케이션에 대해 사용할 수 있습니다.
Github action 및 AWS CodeDeploy로 CI/CD 구축 보라 가기
Github Actios를 사용하여 자동배포하기
CI & CD 소개 코드 버전 관리를 하는 VCS 시스템(Git, SVN 등)에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정을 CI(Continuous Integration - 지속적 통합)이라고 하며,
lympsw12.tistory.com
두 개의 차이점
- 기술 스택 : Docker는 애플리케이션 컨테이너화 기술에 초점을 두고 있으며, CodeDeploy는 배포 자동화 및 관리에 특화되어 있습니다.
- 종속성 : Docker는 컨테이너 이미지에 애플리케이션과 종속성을 포함시키는 반면, CodeDeploy는 애플리케이션 배포를 위해 코드 저장소와 통합하여 사용합니다.
- 배포 환경 : Docker를 사용하는 경우에는 자체 인프라스트럭처에 Docker 환경을 구축해야 하지만, CodeDeploy는 AWS 인프라스트럭처에 직접 구축됩니다.
Docker의 CI/CD 과정
Docker의 CI/CD 과정을 그림으로 한번 표시해 봤습니다.
- 인텔리제이 프로젝트에 Docker file을 만든 후 git에 push 합니다.
- Dockerfile을 빌드해서 docker image 파일을 생성합니다.
- docker image 파일을 docker hub에 push 합니다.
- EC2에서 docker hub에 있는 docker image 파일을 pull 해서 받아옵니다.
- EC2에 있는 컨테이너가 image 파일을 실행시킵니다.
EC2에서 Docker 설치
CodeDeploy는 AWS에서 지원해 주는 방법이라 EC2에 따로 설치해 줄 필요가 없었습니다. 따라서 환경세팅을 할 게 없었습니다. 하지만 docker를 EC2에 설치해줘야 합니다.
참고 : https://insight.infograb.net/docs/aws/installing-docker-on-aws-ec2/
AWS EC2 인스턴스(Ubuntu 18.04 LTS)에 Docker CE 설치 | DevSecOps 구축 컨설팅, 교육, 기술지원 서비스 제공
GitLab 을 AWS EC2에 설치하는 방법을 가이드 합니다. Ubuntu Server 18.04 기준으로 Docker 를 이용해서 GitLab 을 설치해서 사용 할 수 있는 가이드 입니다.
insight.infograb.net
Repository 구성
sudo apt-get update
// apt가 HTTPS을 통해 repository를 사용할 수 있도록 필요한 패키지들을 설치한다.
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
// Docker의 공식 GPG 키를 추가한다.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
// Stable Repository(안정 버전 저장소)를 설정하기 위해 아래 명령어를 사용한다.
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) \
stable"
// 공식 Docker 저장소로부터 설치하는 것인지 확인한다.
sudo apt-cache policy docker-ce
Docker Engine 설치
sudo apt-get update
// Docker Engine과 containerd 최신 버전을 설치한다.
sudo apt-get install docker-ce docker-ce-cli containerd.io
//hello-world 이미지를 구동하여 Docker CE가 정상적으로 설치되었는지 확인한다.
sudo docker run hello-world
//docker가 잘 설치되었는지 확인한다
docker --version
트러블슈팅
나중에 github action으로 docker에 접근할 때 접근할 수 없다는 에러가 뜹니다. 이것은 외부에서 나의 EC2 도커에 접근할 수 없기 때문입니다. 위에서 보면 모두 sudo로 처리했습니다.
즉, sudo 없이 코드들을 처리하고 싶다.
sudo usermod -a -G docker ubuntu
이 명령어를 실행하면 됩니다. 하지만 에러가 뜹니다. Docker 데몬 소켓에 연결하는 동안 권한이 거부되었다는 에러가 발생합니다.
sudo chmod 666 /var/run/docker.sock
그래서 권한을 변경시켜 주면 됩니다.
Docker 파일 생성
Docker 파일은 root에 만들어줘야 합니다. 인텔리제이에서 제일 상단 폴더에 만들어주면 됩니다.
FROM openjdk:17-oracle
COPY ./build/libs/My_Spring_Project-0.0.1-SNAPSHOT.jar My_Spring_Project.jar
ENTRYPOINT ["java", "-jar","-Dspring.profiles.active=prod","My_Spring_Project.jar"]
- FROM
- 내 프로젝트는 자바 17이므로 openjdk:17-oracle을 사용할 것입니다.
- COPY
- COPY는 왼쪽에 있는 파일을 오른쪽에 복사해 주는 명령어입니다.
- ENTRYPOINT
- EC2에서 실행할 명령어입니다.
docker-compose.yml 파일
docker-compose.yml은 컨테이너들을 관리해 주는 역할을 합니다.
이 프로젝트에는 컨테이너를 하나만 사용합니다. Redis 및 다른 것을 사용할 일이 지금은 없습니다.
그러므로 이 파일은 지금은 만들지 않습니다.
GithubAction의 docker-deploy.yml파일
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
- on 속성은 해당 워크플로우가 언제 실행되는지 알려줍니다.
- 나는 master에 push, pr이 올 때 실행하도록 설정했습니다.
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- 자바 17 버전을 사용한다고 설정했습니다.
# 서브 모듈 접근하기
- name: Checkout repo
uses: actions/checkout@v3
with:
token: ${{ secrets.TOKEN }}
submodules: true
# 서브 모듈 변경 점 있으면 update
- name: Git Sumbodule Update
run: |
git pull --recurse-submodules
git submodule update --remote --recursive
- 저는 프로젝트에서 submodule을 사용합니다. 그러므로 submodule 접근과 update를 해줘야 합니다.
서브모듈을 이용해 application관리하기
프로젝트를 하다보면 application에 중요한 정보가 들어갈 때가 많다. 예를 들자면 oauth 로그인 정보나 다른 aws access 정보가 있다. 만약 이게 배포가 된다면 엄청난 보안사고가 일어날 수 있다. 이것
lympsw12.tistory.com
# gradlew 권한 변경
- name: Grant execute permission for gradlew
run : chmod +x gradlew
# 빌드하기 (test부분은 빌드 안함)
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
with:
arguments: clean build -x test
- push나 pr을 보낼 때 현재 github에 올라간 파일을 build 합니다.
- 이때 만든 tdd는 빼고 build 하도록 설정했습니다.
- name: 도커 이미지 빌드
run: docker build -t parksewoong/test:latest .
- Docker에 이미지를 빌드합니다.
- 저는 repository이름을 이렇게 설정해 줬으므로 parksewoong/test의 제일 최근을 build 합니다.
- name: Docker - Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- DockerHub의 로그인하는 과정입니다,
- name: Docker Hub 퍼블리시
run: docker push parksewoong/test:latest
- 빌드한 내용을 parksewoong/test:latest에 push 합니다.
- name: Depoly in AWS ec2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
sudo docker stop $(sudo docker ps -a -q)
sudo docker rm $(sudo docker ps -a -q)
sudo docker pull parksewoong/test:latest
sudo docker run -d -p 8080:8080 --name test-server parksewoong/test:latest
- 이제 위에서 만든 이미지를 EC2에 배포하는 과정입니다.
- host, username, key를 EC2에서 가져와 github의 secrets으로 설정해 줍니다.
- script가 실행되는 부분입니다
- 현재 실행하고 있는 것을 stop 하고 삭제합니다
- 그리고 지금 제일 최근 image를 dockerhub에서 가져옵니다.(pull)
- 그 후 EC2에 있는 Docker 컨테이너에서 실행을 해주면 됩니다.
전체코드
name: Java CI with Gradle
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
# 서브 모듈 접근하기
- name: Checkout repo
uses: actions/checkout@v3
with:
token: ${{ secrets.TOKEN }}
submodules: true
# 서브 모듈 변경 점 있으면 update
- name: Git Sumbodule Update
run: |
git pull --recurse-submodules
git submodule update --remote --recursive
# gradlew 권한 변경
- name: Grant execute permission for gradlew
run : chmod +x gradlew
# 빌드하기 (test부분은 빌드 안함)
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
with:
arguments: clean build -x test
# Docker
- name: 도커 이미지 빌드
run: docker build -t parksewoong/test:latest .
- name: Docker - Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Docker Hub 퍼블리시
run: docker push parksewoong/test:latest
- name: Depoly in AWS ec2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
sudo docker stop $(sudo docker ps -a -q)
sudo docker rm $(sudo docker ps -a -q)
sudo docker pull parksewoong/test:latest
sudo docker run -d -p 8080:8080 --name test-server parksewoong/test:latest
어떻게 보면 CodeDeploy 보다 구현해야 할 코드는 적은 것 같습니다. 하지만 Redis 및 다른 요소들을 사용한다면 고려해야 할 요소들이 더 많아질 것 같습니다. 실제 프로젝트에서는 log 파일도 필요할 것이므로 이 부분도 설정해줘야 합니다.
지금은 제일 간단하게 EC2에 배포하는 것만 했는데 다른 지원해 주는 것들을 더 공부해 봐야겠습니다.
'혼자하는 프로젝트 > 나만의 프로젝트' 카테고리의 다른 글
스프링 시큐리티로 회원가입, 로그인 구현하기 (0) | 2023.06.27 |
---|---|
테스트 코드 공부 (0) | 2023.06.21 |
데이터베이스 정규화 하기 (2) | 2023.04.29 |
OAuth2.0 이란? (2) | 2023.02.07 |
SpringBoot를 이용한 이메일 인증 하기 (0) | 2023.02.06 |