Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save maketheworldwise/120378250d06aaa610eb12d2d94108ce to your computer and use it in GitHub Desktop.
Save maketheworldwise/120378250d06aaa610eb12d2d94108ce to your computer and use it in GitHub Desktop.
EC2 - 무중단 배포 (docker, docker-compose)
docker, docker-compose를 이용한 무중단 배포 구성 (애플리케이션을 실행시 공개되어서는 안되는 내용들이 있다면, 하단의 모든 파일들은 서버에 직접 구성해 놓는 편이 보안적으로 안전)
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#include /etc/nginx/conf.d/*.conf;
upstream application {
least_conn;
server 127.0.0.1:8081 weight=5 max_fails=3 fail_timeout=10s;
server 127.0.0.1:8082 weight=10 max_fails=3 fail_timeout=10s;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://application;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
}
version: '3.7'
services:
nginx:
build:
context: .
dockerfile: Dockerfile_nginx
image: service/nginx:latest
ports:
- "80:80"
container_name: application_nginx
network_mode: "host"
---
# nginx.conf, Dockerfile_nginx, docker-compose.nginx.yml 파일은 같은 경로에 존재
# 서버에서 별도로 실행시켜야 함
$ sudo docker-compose -p nginx -f docker-compose.nginx.yml up -d
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
VOLUME /var/log/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
FROM adoptopenjdk/openjdk11
ARG JAR_FILE=./build/libs/*-SNAPSHOT.jar
COPY $JAR_FILE application.jar
VOLUME ./logs
EXPOSE 8081
ENTRYPOINT java -jar /application.jar
version: '3.7'
services:
application:
build:
context: .
dockerfile: Dockerfile_application
image: service/application:latest
ports:
- "8081:8081"
container_name: application_blue
version: '3.7'
services:
application:
build:
context: .
dockerfile: Dockerfile_application
image: service/application:latest
ports:
- "8082:8081"
container_name: application_green
#!/bin/bash
DOCKER_IMAGE_VERSION=$1
DOCKER_APP_BLUE=application_blue
DOCKER_APP_BLUE_PORT=8081
DOCKER_APP_GREEN=application_green
DOCKER_APP_GREEN_PORT=8082
DOCKER_COMPOSE_FILE_BLUE=docker-compose.blue.yml
DOCKER_COMPOSE_FILE_GREEN=docker-compose.green.yml
# docker-compose 실행 명령어 위치
DOCKER_COMPOSE_COMMAND=/usr/local/bin/docker-compose
EXIST_BLUE=$(${DOCKER_COMPOSE_COMMAND} -p ${DOCKER_APP_BLUE} -f ${DOCKER_COMPOSE_FILE_BLUE} ps | grep ${DOCKER_APP_BLUE})
if [ -n "$EXIST_BLUE" ]; then
echo "> blue down, green up"
${DOCKER_COMPOSE_COMMAND} -p ${DOCKER_APP_GREEN} -f ${DOCKER_COMPOSE_FILE_GREEN} up -d --build
# 구동 예상 시간 20초
sleep 20
# health check
# health check 1번 성공시 blue down
# health check 3번 실패시 green down
for retry_count in {1..3}
do
response=$(curl -s http://localhost:${DOCKER_APP_GREEN_PORT}/health)
up_count=$(echo "$response" | grep 'health' | wc -l)
if [ "$up_count" -ge 1 ]; then
echo "> health check succeed [# $retry_count]"
break
else
echo "> health check failed [# $retry_count]"
fi
if [ "$retry_count" -eq 3 ]; then
echo "> health check failed 3 times"
${DOCKER_COMPOSE_COMMAND} -p ${DOCKER_APP_GREEN} -f ${DOCKER_COMPOSE_FILE_GREEN} down
exit 1
fi
done
${DOCKER_COMPOSE_COMMAND} -p ${DOCKER_APP_BLUE} -f ${DOCKER_COMPOSE_FILE_BLUE} down
else
echo "> green down, blue up"
${DOCKER_COMPOSE_COMMAND} -p ${DOCKER_APP_BLUE} -f ${DOCKER_COMPOSE_FILE_BLUE} up -d --build
# 구동 예상 시간 20초
sleep 20
# health check
# health check 1번 성공시 blue down
# health check 3번 실패시 green down
for retry_count in {1..3}
do
response=$(curl -s http://localhost:${DOCKER_APP_BLUE_PORT}/health)
up_count=$(echo "$response" | grep 'health' | wc -l)
if [ "$up_count" -ge 1 ]; then
echo "> health check succeed [# $retry_count]"
break
else
echo "> health check failed [# $retry_count]"
fi
if [ "$retry_count" -eq 3 ]; then
echo "> health check failed 3 times"
${DOCKER_COMPOSE_COMMAND} -p ${DOCKER_APP_BLUE} -f ${DOCKER_COMPOSE_FILE_BLUE} down
exit 1
fi
done
${DOCKER_COMPOSE_COMMAND} -p ${DOCKER_APP_GREEN} -f ${DOCKER_COMPOSE_FILE_GREEN} down
fi
# 동일한 버전의 이미지가 있을 경우
same_images=$(docker images --format "{{.ID}} {{.Tag}}" | grep ${DOCKER_IMAGE_VERSION} | wc -l)
if [ "$same_images" -ge 1 ]; then
echo "> remove same image"
sudo docker rmi service/application:"${DOCKER_IMAGE_VERSION}"
fi
# 이미지 버전 변경
sudo docker tag service/application:latest service/application:"${DOCKER_IMAGE_VERSION}" # $(date +%Y%m%d%H%M%S)
sudo docker rmi service/application:latest
---
# none 이미지 삭제
#sudo docker rmi $(docker images -q --filter "dangling=true")
---
# 특정 키워드가 태그에 포함된 이미지 삭제
# '--format' 키값 : {{.ID}} {{.Repository}} {{.Tag}} {{.Digest}} {{.CreatedSince}} {{.CreateAt}} {{.Size}}
#docker rmi $(docker images --format "{{.ID}} {{.Tag}}" | grep "KEYWORD" | awk '{print $1}')
@maketheworldwise
Copy link
Author

maketheworldwise commented Jun 10, 2022

전체 구성도 :

infra

Jenkins 설정 :

Jenkins를 EC2에 Docker로 설치하는 것이 아닌 내부에 직접 설치하는 방향으로 진행했을 때, 배포 스크립트를 실행시키기 위한 설정

  • Execute shell 항목은 위의 모든 파일들이 같은 경로에 존재한다는 가정

jenkins

  • Execute shell 항목은 위의 모든 파일들이 Jenkins의 workspace 경로에 존재한다는 가정

jenkins_execute

@maketheworldwise
Copy link
Author

로그의 경우 AWS 서비스를 이용한다면 appender 설정으로 CloudWatch에 기록되도록 구성하면 됨

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment