CI/CD 단계별 구축하기
업데이트:
CI/CD란?
테스트(Test),통합(Merge),배포(Deploy)의 과정을 자동화하는 것을 의미합니다.
배포를 할때 직접 컴퓨터 서버에 접속해서 새로운 코드를 다운받아 실행시켜주어야 한다.
코드를 수정하고 나서 이것을 서버에 반영을 하고 싶다면, 다시 앞에 언급했던 과정(서버에 접속 -> 새로운 코드 다운 -> 실행)을 반복해야하므로 이러한 반복을 자동화 시키기 위한 것이라고 볼 수 있습니다.
CI/CD tool들
- GitHub Actions
- Jenkins
- Circle Cl
- Travis Cl
GitHub Actions란?
로직을 실행시킬 수 있는 컴퓨터라고 보면 됩니다. CI/CD과정에서는 “빌드,테스트,배포” 로직을 실행시키는 역할을 합니다.
CI/CD의 흐름!
1.코드 커밋 2.gihub push 3.push하면 바로 github actions에서 작성한 로직 실행 4.서버에서 배포된 최신 코드로 서버 재실행
Github Actions 기본 문법
① .github 폴더 생성
② 생성한 폴더 하위에 workflows 생성
위 폴더들의 이름은 틀리면 안되고, 루트 경로에 있어야 함.
③ workflows 하위에 yml 파일 만듦
④ Github Actions에서 실행할 코드들 작성
// Workflow라고 하자
name: Github Actions 실행시켜보기 # 워크플로우의 이름
# 실행되는 시점을 설정 할 수 있음.
on:
push:
branches:
- main # main이라는 브랜치로 push 될 때 아래 workflow를 실행한다는 의미
# 하나의 워크플로우는 1개 이상의 job으로 구성됨.
# 여러 JOB은 기본적으로 병렬적으로 수행된다.
jobs:
My-Deploy-Job: ## 임의대로 붙여도 됨. JOB 식별 id라고 보면됨.
runs-on: ubuntu-latest # JOB을 실행하는 ubuntu 환경/ 가장 최신 버전(latest)
# Step: 특정 작업을 수행하는 가장 작은 단위
# Job은 여러 Step들로 구성되어 있다.
# $GITHUB_SHA 커밋 ID
# $GITHUB_REPOSITORY 레포지토리 명
# secrets는 레포지토리 세팅탭에서 변수 값지정 가능
steps:
- name: Hello World 찍기
run: echo "Hello World"
- name: 여러 명령어 문장 작성하기
run: |
echo "Good"
echo "Perfect"
- name: Gihub Actions 자체에 저장되어 있는 변수 사용해서 출력
run: |
echo $GITHUB_SHA
echo $GITHUB_REPOSITORY
- name: 아무한테 노출이 되면 안 되는 값
run: |
echo $
echo $
Github Actions 흐름
- 대부분의 CI/CD는 전체 프로젝트를 통째로 갈아끼우는 방식 사용
원래 순서
1.ec2 생성
2.서버에 접속
3.sudo apt-get update
4.java 설치
5.git clone
6.프로젝트 빌드
- cd build/libs
- ./gradlew clean build
- nohup java -jar cicd-test-0.0.1-SNAPSHOT.jar &
- sudo lsof -i:8080 -> PID 확인
- sudo fuser -k -n tcp 8080 -> PID로 프로세스 종료
해당 사항들을 자동화 시키는 것이 CI/CD입니다.
Tips
- git config –global credential.helper store
- git push 할 때마다 계정과 비밀번호를 입력하는 것이 귀찮다면 이 명령어를 입력하면 된다.
1. Github Actions를 이용한 개인용 CI/CD
name: Deploy To EC2
on:
push:
branches:
- main
# uses 에는 사용할 라이브러리 이름과 버전을 적어준다.
# sudo fuser -k -n tcp 8080 8080 포트를 사용하는 프로세스를 종료
# || true : 에러가 발생해도 계속 실행
# ./output.log 2>&1 : output.log 파일에 로그를 저장
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: SSH(원격 접속)로 EC2에 접속
uses: appleboy/ssh-action@v1.0.3
with:
host: $
username: $
key: $
script_stop: true
script: |
cd /home/ubuntu/github-actions-pr-2
git pull origin main
./gradlew clean build
sudo fuser -k -n tcp 8080 || true
nohup java -jar build/libs/*SNAPSHOT.jar > ./output.log 2>&1 &
yml 파일을 추적하지 않고 자동화하기
name: Deploy To EC2
on:
push:
branches:
- main
# uses 에는 사용할 라이브러리 이름과 버전을 적어준다.
# sudo fuser -k -n tcp 8080 8080 포트를 사용하는 프로세스를 종료
# || true : 에러가 발생해도 계속 실행
# ./output.log 2>&1 : output.log 파일에 로그를 저장
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: SSH(원격 접속)로 EC2에 접속
uses: appleboy/ssh-action@v1.0.3
env:
APPLICATION_PROPERTIES: $ ## application.yml 파일을 secrets에 복사 붙여넣기
with:
host: $
username: $
key: $
envs: APPLICATION_PROPERTIES ## 환경변수로 사용
script_stop: true
script: |
cd /home/ubuntu/github-actions-pr-2
rm -rf scr/main/resources/application.yml || true
rm -rf scr/main/resources/application.properties || true
git pull origin main
echo "$APPLICATION_PROPERTIES" > src/main/resources/application.yml
## application.yml 파일을 생성
./gradlew clean build
sudo fuser -k -n tcp 8080 || true
nohup java -jar build/libs/*SNAPSHOT.jar > ./output.log 2>&1 &
application.yml관리하기
- APPLICATION_PROPERTIES에 복사 붙여넣기
- 생성된 것 확인
해당 부분은 수동으로 진행해야 한다.
참고
- git rm -r –cached (#git에 올라간 파일 삭제)
2. Github Actions를 이용한 팀프로젝트 CI/CD
name: Deploy To EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository에 올린 파일들을 불러오기
uses: actions/checkout@v4
- name: JDK 17버전 설치
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: application.yml 파일 만들기
run: echo "$" > src/main/resources/application.yml
- name: 테스트 및 빌드하기
run: ./gradlew clean build
- name: 빌드된 파일 이름 변경하기
run: mv ./build/libs/*SNAPSHOT.jar ./project.jar
## 업데이트된 파일을 tobe폴더에 넣어두기
- name: SCP로 EC2에 빌드된 파일 전송하기
uses: appleboy/scp-action@v0.1.7
with:
host: $
username: $
key: $
source: project.jar
target: /home/ubuntu/cicd-server/tobe
## tobe폴더에 있는 파일을 current폴더로 옮기기
- name: SSH(원격 접속)로 EC2에 접속
uses: appleboy/ssh-action@v1.0.3
env:
APPLICATION_PROPERTIES: $
with:
host: $
username: $
key: $
script: |
rm -rf /home/ubuntu/cicd-server/current
mkdir /home/ubuntu/cicd-server/current
mv /home/ubuntu/cicd-server/tobe/project.jar /home/ubuntu/cicd-server/current/project.jar
cd /home/ubuntu/cicd-server/current
sudo fuser -k -n tcp 8080 || true
nohup java -jar project.jar > ./output.log 2>&1 &
rm -rf /home/ubuntu/cicd-server/tobe
-
이 current 파일에 기존에 실행시킨 jar파일이 있기 때문에
- 폴더를 지워버리고 새롭게 만들어서 옛날 거를 이제 없애버리고 새로운 거를 current 폴더로 옮겨버리는 과정
- 이 과정을 통해서 기존 서버 종료하고 새롭게 전달한 jar 파일 실행
3. Github Actions를 이용한 팀프로젝트 CI/CD(2) - Code Deploy
- 많은 서버에 있는 EC2에 쉽게 할 수 있도록 해주고, 무중단 배포 기능이 내재되어 있다.
Code Deploy의 흐름
1) IAM Role 생성
1-1) AWS 서비스 -> IAM -> 역할 -> 역할 생성
1-2) code Deploy 선택 -> 다음 -> 선택되어 있는 권한 그대로 다음 -> 역할 이름 입력 -> 역할 생성
2) Code Deploy 생성
2-1) AWS 서비스 -> Code Deploy -> 애플리케이션 -> 애플리케이션 생성
2-2) 애플리케이션 이름 입력 -> 컴퓨팅 플랫폼에서 EC2/온프레미스 선택 -> 애플리케이션 생성
2-3) 배포 그룹 생성 (배포 그룹? 배포시에 다양한 환경[production,develop,staging]이 있는데, 그 환경을 구분해서 관리하는 것) -> 배포 그룹 이름 입력 -> 서비스 역할 선택 (만들어 놨던 역할 선택)
2-4) 인스턴스로 선택하고(여기서는 EC2인스턴스니깐) -> 태그 선택 -> NAME -> 값 선택은 EC2 인스턴스의 이름이 나와있기 때문에 이름을 선택하면 된다. -> 오토스케일링은 사용할때만 체크 -> 배포 그룹 생성
3) EC2는 S3에 있는 파일을 받아서 실행시키는 것이기 때문에 S3에 접근할 수 있는 권한 필요 -> EC2에 IAM Role을 부여
3-1) S3에 접근할 수 있는 권한을 따로 생성
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:Get*",
"s3:List*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
3-2) EC2에 IAM Role을 부여 -> 만들어준 정책 선택 -> 역할 생성
3-3) EC2에 IAM Role을 부여 -> 인스턴스 -> 보안 -> 업데이트
4) Code Deploy Agent 설치
4-1) EC2에 접속 -> Code Deploy Agent 설치
sudo apt update && \
sudo apt install -y ruby-full wget && \
cd /home/ubuntu && \
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install && \
chmod +x ./install && \
sudo ./install auto
4-2) 설치 확인
systemctl status codedeploy-agent
5) Github Actions를 위한 IAM Role 생성
5-1) AWS 서비스 -> IAM -> 사용자 -> 사용자 추가
5-2) 사용자 이름 입력 -> 다음 -> 직접 연결 선택 -> AmazonS3FullAccess, AWSCodeDeployFullAccess 선택 -> 사용자 만들기
5-3) 만들어진 사용자에서 보안자격증명 탭 -> 액세스 키 만들기 -> aws 외부에서 실행되는 애플리케이션 선택 -> 액세스 키 ID, 비밀 액세스 키 복사 -> Github Secrets에 추가
6) 빌드 파일을 저장할 S3 버킷 생성
6-1) AWS 서비스 -> S3 -> 버킷 생성
7) EC2접속
7-1) EC2에 접속 -> 기존 파일들 삭제
rm -rf cicd-server
rm -rf install ## Code Deploy Agent 설치 파일 삭제
8) 프로젝트 폴터 루트에 appspec.yml 파일 생성
version: 0.0
os: linux
## code deploy가 빌드 파일을 S3에 저장을 할건데, S3에 저장된 파일을 EC2에 저장할 경로를 적어준다.
## files에는 프로젝트 파일이 저장된 경로와 EC2에 저장될 경로를 적어준다.
files:
- source: /
destination: /home/ubuntu/cicd-server
## EC2에 저장된 파일의 권한을 설정
permissions:
- object: /
owner: ubuntu
group: ubuntu
## EC2가 S3로부터 빌드파일을 다운 받고 실행시키기 위한 명령어를 적어준다.
## hooks에는 EC2에 파일을 저장하고 실행시키기 위한 명령어를 적어준다.
hooks:
ApplicationStart:
- location: scripts/start-server.sh
timeout: 60
runas: ubuntu
9) 프로젝트 폴더 루트에 scripts 폴더 생성
9-1) start-server.sh 파일 생성
#!/bin/bash
echo "---------------서버 시작---------------"
cd /home/ubuntu/cicd-server
sudo fuser -k -bin tcp 8080 || true
nohup java -jar project.jar > ./ouput.log 2>&1 &
echo "---------------서버 배포 완료---------------"
10) Github Actions yml 파일 수정
name: Deploy To EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository에 올린 파일들을 불러오기
uses: actions/checkout@v4
- name: JDK 17버전 설치
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: application.yml 파일 만들기
run: echo "$" > src/main/resources/application.yml
- name: 테스트 및 빌드하기
run: ./gradlew clean build
- name: 빌드된 파일 이름 변경하기
run: mv ./build/libs/*SNAPSHOT.jar ./project.jar
- name: 파일들 압축하기 # 압축 파일명은 Github SHA로 설정 (해당 파일은 Github Actions에서 생성됨)
run: tar -czvf $GITHUB_SHA.tar.gz project.jar appspec.yml scripts
- name: Github Actions가 AWS에 로그인 할 수 있도록 설정하기
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ap-northeast-2
aws-access-key-id: $
aws-secret-access-key: $
- name: S3에 압축된 파일 업로드하기
run: aws s3 cp --region ap-northeast-2 $GITHUB_SHA.tar.gz s3://cicd-server/$GITHUB_SHA.tar.gz
- name: CodeDeploy 활용하여 EC2에 프로젝트 코드를 배포시키기
run: aws deploy create-deployment ## CodeDeploy에서 배포실행 명령어
--application-name cicd-server
--deployment-config-name CodeDeployDefault.AllAtOnce ## 자세한 설명을 덧붙이자면, 배포 전략을 설정하는 것이다. AllAtOnce는 한번에 배포하는 것이다.(서버를 한대를 기준으로 하기 때문에 한개를 그냥 그대로 교체하는 방식)
--deployment-group-name Production
--s3-location bucket=cicd-server,bundleType=tgz,key=$GITHUB_SHA.tar.gz ## S3에 저장된 파일을 가져오는 것
## 업데이트된 파일을 tobe폴더에 넣어두기
- name: SCP로 EC2에 빌드된 파일 전송하기
uses: appleboy/scp-action@v0.1.7
with:
host: $
username: $
key: $
source: project.jar
target: /home/ubuntu/cicd-server/tobe
## tobe폴더에 있는 파일을 current폴더로 옮기기
- name: SSH(원격 접속)로 EC2에 접속
uses: appleboy/ssh-action@v1.0.3
env:
APPLICATION_PROPERTIES: $
with:
host: $
username: $
key: $
script: |
rm -rf /home/ubuntu/cicd-server/current
mkdir /home/ubuntu/cicd-server/current
mv /home/ubuntu/cicd-server/tobe/project.jar /home/ubuntu/cicd-server/current/project.jar
cd /home/ubuntu/cicd-server/current
sudo fuser -k -n tcp 8080 || true
nohup java -jar project.jar > ./output.log 2>&1 &
rm -rf /home/ubuntu/cicd-server/tobe
11) 배포된 것 확인
11-1) AWS 서비스 -> Code Deploy -> 배포 -> 배포 생성 확인
** EC2에 있는 scripts 로그 확인 가능
cd /opt/codedeploy-agent/deployment-root
cd ./숫자와 영어함께 있는 폴더
cd ./다시 숫자와 영어함께 있는 폴더
cd ./logs
cat ./scripts.log
4. Github Actions를 이용한 팀프로젝트 CI/CD(3) - 도커를 이용한 배포
- ECR은 도커 이미지를 저장해 놓고 보관하는 도커허브와 같은 용도이다.
- 여러 EC2 인스턴스에 배포하거나 무중단 배포를 해야한다면 복잡한 구조이다.
1) EC2에 도커 설치
1-1) EC2에 접속 -> 도커 설치
sudo apt-get update && \
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && \
sudo apt-key fingerprint 0EBFCD88 && \
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && \
sudo apt-get update && \
sudo apt-get install -y docker-ce && \
sudo usermod -aG docker ubuntu && \
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
sudo chmod +x /usr/local/bin/docker-compose && \
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
2) Github Actions 권한 설정
2-1) AWS 서비스 -> IAM -> 기존 사용자에서 권한 추가 -> AmazonEC2ContainerRegistryFullAccess, AmazonEC2ContainerServiceFullAccess 선택 -> 권한 추가
3) ECR 생성
3-1) AWS 서비스 -> ECR -> private 리포지토리 생성
3-2) 프라이빗 레포지토리에 접근할 수 있게 세팅
$ sudo apt update
$ sudo apt install amazon-ecr-credential-helper
$ cd ~
$ mkdir .docker
$ cd .docker
$ touch config.json
$ vi config.json
{
"credsStore": "ecr-login"
}
- 이렇게 하면 도커 이미지를 ECR에 저장할 때 자동으로 로그인이 된다.
3-3) EC2가 ECR에 접근할 수 있게 권한 부여
4) Github Actions yml 파일 수정
name: Deploy To EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository 파일 불러오기
uses: actions/checkout@v4
- name: JDK17 설치
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: application.yml 파일 생성
run: echo "$" > ./src/main/resources/application.yml
- name: 빌드 그리고 테스트
run: ./gradlew clean build
- name: AWS에 접근할 수 있게 설정
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ap-northeast-2
aws-access-key-id: $
aws-secret-access-key: $
- name: ECR에 로그인
id: login-ecr
run: aws-actions/amazon-ecr-login@v2
- name: Docker 이미지 생성
run: docker build -t cicd-server .
- name: Docker 이미지 tag 붙이기
run: docker tag cicd-server $/cicd-server:latest
- name: ECR에 도커 이미지 push
run: docker push $/cicd-server:latest
- name: SSH로 EC2에 접속
uses: appleboy/ssh-action@v1.0.3
with:
host: $
username: $
key: $
script: |
docker stop cicd-server || true
docker rm cicd-server || true
docker pull $/cicd-server:latest
docker run -d -p 8080:8080 --name cicd-server $/cicd-server:latest
- 위에 코드들로 실행했지만, 에러가 발생하였다. 그래서 아래 코드로 수정하였다.
name: Deploy To EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository 파일 불러오기
uses: actions/checkout@v4
- name: JDK17 설치
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: application.yml 파일 생성
run: echo "$" > ./src/main/resources/application.yml
- name: 빌드 그리고 테스트
run: ./gradlew clean build
- name: AWS에 접근할 수 있게 설정
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ap-northeast-2
aws-access-key-id: $
aws-secret-access-key: $
- name: ECR에 로그인
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Docker 이미지 생성
run: docker build -t cicd-server .
- name: Docker 이미지 tag 붙이기
run: docker tag cicd-server $/cicd-server:latest
- name: ECR에 도커 이미지 push
run: docker push $/cicd-server:latest
- name: SSH로 EC2에 접속하기
uses: appleboy/ssh-action@v1.2.0
with:
host: $
username: $
key: $
script_stop: true
script: |
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $
docker stop cicd-server || true
docker rm cicd-server || true
docker pull $/cicd-server:latest
docker run -d --name cicd-server -p 8080:8080 $/cicd-server:latest
- 위 코드를 실행하기 전에, aws 로그인 cli를 설치해야 한다.
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
sudo apt install unzip # unzip이 없다면 설치
unzip awscliv2.zip
sudo ./aws/install
5. Github Actions를 이용한 팀프로젝트 CI/CD(4) - Code Deploy + 도커
1) Github Actions yml 파일 수정
name: Deploy To EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository 파일 불러오기
uses: actions/checkout@v4
- name: JDK17 설치
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: application.yml 파일 생성
run: echo "$" > ./src/main/resources/application.yml
- name: 빌드 그리고 테스트
run: ./gradlew clean build
- name: AWS에 접근할 수 있게 설정
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ap-northeast-2
aws-access-key-id: $
aws-secret-access-key: $
- name: ECR에 로그인
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Docker 이미지 생성
run: docker build -t cicd-server .
- name: Docker 이미지 tag 붙이기
run: docker tag cicd-server $/cicd-server:latest
- name: ECR에 도커 이미지 push
run: docker push $/cicd-server:latest
- name: 파일 압축하기
run: tar -czvf $GITHUB_SHA.tar.gz appspec.yml scripts
- name: S3에 프로젝트 폴더 업로드하기
run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.tar.gz s3://cicd-server/$GITHUB_SHA.tar.gz
- name: CodeDeploy를 활용해 EC2에 프로젝트 코드 배포
run: aws deploy create-deployment
--application-name cicd-server
--deployment-group-name Production
--deployment-config-name CodeDeployDefault.AllAtOnce
--s3-location bucket=cicd-server,bundleType=tgz,key=$GITHUB_SHA.tar.gz
2) scripts 폴더에 start-server.sh 파일 수정
#!/bin/bash
echo "---------------서버 시작---------------"
docker stop cicd-server || true
docker rm cicd-server || true
docker pull 730335259243.dkr.ecr.ap-northeast-2.amazonaws.com/cicd-server:latest ## ecr 주소
docker run -d --name cicd-server -p 8080:8080 730335259243.dkr.ecr.ap-northeast-2.amazonaws.com/cicd-server:latest
echo "---------------서버 배포 완료---------------"
댓글남기기