728x90
반응형
서비스를 배포할 인스턴스를 생성하고 CodeDeploy 동작을 인식하기 위한 태그를 추가합니다.
- 인스턴스 시작 클릭
- Amazon Linux 선택
- 인스턴스 유형, 키 페어(로그인에 사용될 키, 새로 생성 했으면 꼭!!! 로컬에 따로 저장해야 함), 네트워크 설정
- 네트워크 설정(나중에 필요에 따라 보안 규칙 수정), 스토리지 30GB로 설정(30GB까지 무료)
- 인스턴스에서 우클릭 한 후 태그 관리 클릭
- 행동을 식별할 수 있는 태그 추가(값은 입력하지 않아도 됨). Github Actions 스크립트에서 이 태그를 이용해 Ec2를 식별하고 Runner를 실행시킴.
IAM에서 사용자, 역할 추가, 사용자의 키를 Github Actions에 등록
CodeDeploy에 사용될 IAM 작업자를 생성하고 인스턴스에 적용할 역할을 생성합니다.
- IAM 메뉴에서 사용자 클릭 후 사용자 추가 클릭
- 이름 입력, 액세스 키 선택 후 다음:권한 버튼 클릭
- 기존 정책 직접 연결 클릭 후
- AmazonS3FullAccess
- AWSCodeDeployFullAccess
- 권한 선택 후 다음:태그 클릭
- 태그는 생성하지 않아도 됨, 다음: 검토 클릭
- 아래와 같이 설정 되었다면 사용자 만들기 클릭, 사용자 생성 완료!
- 사용자가 생성된 후에 Access key ID와 Secret access key는 꼭 로컬 혹은 안전한 위치에 따로 저장해두도록 하자. 이 페이지를 지나가면 다시는 볼 수 없다.
- 깃헙 레포지토리로 이동한 후 Settings 클릭, Secrets → Actions 탭에서
- New Repository secret을 클릭해서 아래 값들을 추가해준다.
- AWS_ACCESS_KEY_ID: IAM 사용자 Access key ID
- AWS_SECRET_ACCESS_KEY: IAM 사용자 Secret access key
- AWS_REGION: 현재 AWS의 인스턴스가 위치한 region 값 (예: ap-northeast-2)
- IAM에서 역할 클릭 후 역할 만들기 클릭
- 다른 AWS 서비스의 사용 사례에서 CodeDeploy 검색해서 선택 후 CodeDeploy 라디오 박스 선택, 다음 버튼 클릭
- 아래 화면과 동일하면 다음 클릭
- 수정할 것 없이 역할 생성 클릭, 역할 생성 완료!
- instance에 우클릭 후 보안 → IAM 역할 수정 클릭
- 미리 생성한 IAM 역할 선택해준 뒤 IAM 역할 업데이트 클릭
S3 생성
Github Actions에서 만든 zip 파일을 업로드 할 S3 Bucket을 생성합니다. 버킷 이름은 AWS 리전 안에서 고유하므로 서비스 이름과 연관 지어서 짓습니다.
- S3에서 버킷 만들기 선택(s3이름은 고유하므로 가림)
- 아래 모든 퍼블릭 엑세스 차단이 선택되어 있는지 확인한 후 다른 설정 수정할 것 없이 버킷 만들기 클릭, S3 버킷 생성 완료!
Github Actions에 Runner 등록 및 Ec2에 추가
- 레포지토리로 이동해서 Settings의 탭에서 Actions → Runners 클릭, New self-hosted runner 클릭
- 리눅스 클릭한 후 Ec2에 접속해 아래 명령어를 차례대로 실행
- $ echo "~~~~~~ actions-runner-linux-x64-2.299.1.tar.gz" | shasum -a 256 -c 명령어는 해시 확인하는 명령어이므로 스킵해도 됨(aws linux에 shasum 라이브러리가 없어서 실행 불가능, 외부 다른 방법으로 실행해서 확인해도 됨)
- ./run.sh 생성 시 4가지 항목이 뜸.
- 엔터, 엔터, This runner will have the following labels에서 ec2에 부여해준 태그를 추가, 엔터
- nohup ./run.sh & 입력해서 러너가 백그라운드에서 돌게 해줌
- Runner 생성 완료!
CodeDeploy 설정
S3에서 코드를 가져와서 Ec2에 배포하기 위해서 CodeDeploy를 설정해줍니다.
- CodeDeploy의 애플리케이션 탭에서 애플리케이션 생성 버튼 클릭
- 애플리케이션 이름을 입력하고 EC2/온프레미스 선택, 애플리케이션 생성 클릭
- 생성한 애플리케이션 클릭
- 배포 그룹 생성 클릭
- 배포 그룹 이름 입력, 사전에 생성해준 서비스 역할 선택
- 환경 구성을 선택한 후 Amazon EC2 인스턴스 클릭, Ec2에 생성해준 태그를 입력
- 사전에 설정한 로드 밸런서가 없다면 배포 그룹 생성 버튼 클릭, CodeDeploy 설정 완료!
- Ec2에 CodeDeploy Agent 설치: https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/codedeploy-agent-operations-install-linux.html
- 아래 코드를 복사해서 쉘에 붙여 넣어 실행시켜줍니다.
sudo yum update
sudo yum install ruby
sudo yum install wget
cd /home/ec2-user
wget <https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install>
chmod +x ./install
sudo ./install auto
sudo service codedeploy-agent status
- "error: No AWS CodeDeploy agent running"와 같은 메시지가 표시되면 서비스를 시작하고 다음 두 명령을 한 번에 하나씩 실행합니다.
sudo service codedeploy-agent start
sudo service codedeploy-agent status
Github Actions 배포 스크립트 설정
Github에서 정해진 동작(push, pull request)이 발생했을 때 실행될 스크립트를 작성합니다.
- 레포지토리의 Actions 탭에서 New workflow 버튼 클릭
- set up a workflow yourself 클릭
- 아래와 같이 스크립트 입력(스크립트 파일 아래에 있음)
- 에디터에서 yaml 문법을 지원해주는 익스텐션 설치를 권장함.
- 더 자세하게 알고 싶다면 https://zzsza.github.io/development/2020/06/06/github-action/
- 설정하는 법 출처: https://goodgid.github.io/Github-Action-CI-CD-Workflows/
- env는 스크립트에서 동적으로 설정한 변수
- S3_BUCKET_NAME: S3 버킷의 이름을 그대로 입력
- CODE_DEPLOY_APPLICATION_NAME: CodeDeploy 이름을 그대로 입력
- CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: CodeDeploy 배포 그룹 이름을 그대로 입력
- deploy의 runs-on에 Ec2에 등록해준 태그를 입력
- docker-compose 등의 키워드를 모른다면 docker 페이지에서 학습하고 오기
- 아래 스크립트는 Spring Boot의 예시
name: CI-CD prod
on:
push:
branches: [main]
env:
S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}
CODE_DEPLOY_APPLICATION_NAME: ${{ secrets.AWS_CODEDEPLOY_NAME }}
CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: ${{ secrets.AWS_CODEDEPLOY_GROUP_NAME }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@master
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: "17"
distribution: "temurin"
- 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-
- name: Make .env
run: |
touch ./.env
echo "${{ secrets.DOTENV }}" > ./.env
shell: bash
- name: Make application.yml
run: |
cd ./src/main/resources
touch ./application.yml
echo "${{ secrets.APPLICATION_YML }}" > ./application.yml
shell: bash
- name: Make schema.sql
run: |
mkdir ./src/main/resources/db
cd ./src/main/resources/db
touch ./schema.sql
echo "${{ secrets.SCHEMA_SQL }}" > ./schema.sql
shell: bash
- name: Make data.sql
run: |
cd ./src/main/resources/db
touch ./data.sql
echo "${{ secrets.DATA_SQL }}" > ./data.sql
shell: bash
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: |
./gradlew build
# 수정
- name: Make zip file
run: zip -r ./$GITHUB_SHA.zip .
shell: bash
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Upload to S3
run: aws s3 cp --region $AWS_REGION ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip
# 추가
- name: Code Deploy
run: |
aws deploy create-deployment \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
--s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$GITHUB_SHA.zip
run:
needs: deploy # build 후에 실행되도록 정의
runs-on: [admin-inspection-api-prod] # AWS ./configure에서 사용할 label명
steps:
- uses: actions/checkout@v3
- name: Run deploy.sh
run: |
cd /home/ec2-user/orderhero-admin-inspection-api
sudo chmod 777 ./deploy.sh
sudo chmod 777 ./down.sh
sudo chmod 777 ./logging.sh
./deploy.sh
- 배포하기 위한 deploy.sh 생성
#!/bin/bash
cd /home/ec2-user/orderhero-admin-inspection-api
DOCKER_APP_NAME=spring
# 실행중인 blue가 있는지
EXIST_BLUE=$(docker ps | grep spring-blue)
# 실행중인 nginx가 있는지
EXIST_NGINX=$(docker ps | grep nginx)
# 실행중인 postgres가 있는지
EXIST_NGINX=$(docker ps | grep postgres)
# 실행중인 kafka가 있는지
EXIST_KAFKA=$(docker ps | grep kafka)
health_check() {
RESPONSE=$(curl -s http://127.0.0.1:$2)
# 헬스 체크
echo "$3 health check: $IDLE_PORT count: $1... "
echo "response: $RESPONSE"
if [ -n "$RESPONSE" ]; then
echo "$3 down"
docker-compose -p ${DOCKER_APP_NAME}-$3 -f docker-compose.green.yml down
docker image prune -af # 사용하지 않는 이미지 삭제
echo "$3 down complete"
exit
fi
sleep 3
}
# nginx 콘테이너가 없으면 빌드
if [ -z "$EXIST_NGINX" ]; then
docker-compose -p nginx -f docker-compose.nginx.yml up --build -d
fi
# postgres 콘테이너가 없으면 빌드
if [ -z "$EXIST_PG" ]; then
docker-compose -p postgres -f docker-compose.postgres.yml up --build -d
fi
# kafka 콘테이너가 없으면 빌드
if [ -z "$EXIST_KAFKA" ]; then
rm -rf ./logs/kafka1
rm -rf ./logs/kafka2
docker-compose -p kafka -f docker-compose.kafka.yml up --build -d
fi
# green이 실행중이면 blue up
if [ -z "$EXIST_BLUE" ]; then
echo "blue up"
docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml up -d --build
IDLE_PORT=8081
echo "blue up complete"
for RETRY_COUNT in {1..20}; do
health_check $RETRY_COUNT $IDLE_PORT "green"
done
echo "Failed to health check. Please check docker container is running."
# blue가 실행중이면 green up
else
echo "green up"
docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml up -d --build
IDLE_PORT=8082
echo "green up complete"
for RETRY_COUNT in {1..20}; do
health_check $RETRY_COUNT $IDLE_PORT "blue"
done
echo "Failed to health check. Please check docker container is running."
fi
- appspec.yml 을 Ec2에 접속해서 프로젝트의 루트 폴더에 생성
- 자세한 사항: https://goodgid.github.io/Github-Action-CI-CD-CodeDeploy-App-Spec-File/
version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/dl-orderhero-settlement
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
위의 환경 변수들은 아래와 같이 설정한다.
- 깃헙 레포지토리 홈페이지에서 settings > secrets and variables > actions 클릭
- New repository secret 클릭
- Name에 키 이름, Secret에 값 입력
아래 yml 파일들은 모두 스프링 프로젝트의 루트 폴더에 만들어준다.
- docker-compose.blue.yml
# docker-compose.yml
version: "3.9"
#blue
services:
api:
container_name: spring-blue
# restart: always
build: .
ports:
- "8081:8080"
volumes:
- ./logs:/app/logs
- docker-compose.green.yml
# docker-compose.yml
version: "3.9"
#green
services:
api:
container_name: spring-green
# restart: always
build: .
ports:
- "8082:8080"
volumes:
- ./logs:/app/logs
- Dockerfile
FROM openjdk:17
WORKDIR /app
COPY ./build/libs/inspection-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
- docker-compose.nginx.yml
version: "3.9"
services:
nginx:
container_name: nginx
restart: always
image: nginx:1.15
volumes:
- ./nginx/default.prod.conf:/etc/nginx/conf.d/default.conf
ports:
- 80:80
- 443:443
- default.prod.conf
upstream backend {
# ip_hash;
least_conn;
server localhost:8081 weight=1 max_fails=1 fail_timeout=3s;
server localhost:8082 weight=1 max_fails=1 fail_timeout=3s;
server 172.17.0.1:8081 weight=1 max_fails=1 fail_timeout=3s;
server 172.17.0.1:8082 weight=1 max_fails=1 fail_timeout=3s;
}
server {
listen 80;
listen [::]:80;
listen 443;
server_name localhost;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
# if ($http_x_forwarded_proto != 'https') {
# return 301 https://$host$request_uri;
# }
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://backend/;
proxy_redirect off;
}
}
- docker-compose.postgres.yml
version: "3.9"
services:
postgres:
container_name: postgres
image: postgres:15.1-alpine
restart: always
ports:
- 5432:5432
volumes:
- ./postgresql/data:/var/lib/postgresql/data
env_file:
- ./.env
스크립트의 양이 많고, deploy.sh를 어떻게 짜느냐에 따라서 헬스 체크, 커넥션 체크 등 추가적으로 로직이 들어갈 수 있는 만큼 양이 많고 복잡하지만 각 스크립트를 확인하면서 단계적으로 적용하면 어려움 없이 적용할 수 있다.
728x90
반응형
'Devops > Github Actions' 카테고리의 다른 글
Git 테스팅 및 CICD 워크플로우 (0) | 2023.02.02 |
---|---|
Github Actions AWS CICD Workflow (0) | 2023.01.31 |