Skip to content

Commit

Permalink
Merge branch 'leave-git-commit-sha-on-labels'
Browse files Browse the repository at this point in the history
  • Loading branch information
patternhelloworld committed Nov 14, 2024
2 parents 0977302 + 2ba4d37 commit 812091c
Show file tree
Hide file tree
Showing 28 changed files with 519 additions and 137 deletions.
4 changes: 4 additions & 0 deletions .env.example.local
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ GOOD_APP_HEALTH_CHECK_PATTERN=xxx
# This is for environment variables for docker-compose-app-${app_env}.
DOCKER_COMPOSE_ENVIRONMENT={"XDEBUG_CONFIG":"idekey=IDE_DEBUG","PHP_IDE_CONFIG":"serverName=laravel-crud-boilerplate"}
DOCKER_BUILD_ARGS={}
DOCKER_BUILD_LABELS=[]
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=

DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=[]
DOCKER_COMPOSE_HOST_VOLUME_CHECK=false

NGINX_CLIENT_MAX_BODY_SIZE=50M

Expand Down
6 changes: 5 additions & 1 deletion .env.example.real
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@ GOOD_APP_HEALTH_CHECK_PATTERN=xxx
# This is for environment variables for docker-compose-app-${app_env}.
DOCKER_COMPOSE_ENVIRONMENT={}
DOCKER_BUILD_ARGS={}
DOCKER_BUILD_LABELS=[]
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=

# This is overwritten on docker-compose-${project_name}-${app_env}.yml
DOCKER_COMPOSE_REAL_SELECTIVE_VOLUMES=[]
# This is added on docker-compose-${project_name}-nginx.yml
DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=["./shared/nginx-error-logs:/var/log/nginx"]

# Check if the host folder or file exists
DOCKER_COMPOSE_HOST_VOLUME_CHECK=false

NGINX_CLIENT_MAX_BODY_SIZE=50M

Expand Down
4 changes: 4 additions & 0 deletions .env.java.local
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ DOCKER_COMPOSE_ENVIRONMENT={"TZ":"Asia/Seoul"}
# This goes with "docker build ... in the 'run.sh' script file", and the command always contain "HOST_IP" and "APP_ENV" above.
# docker exec -it CONTAINER_NAME cat /var/log/env_build_args.log
DOCKER_BUILD_ARGS={"DOCKER_BUILDKIT":"1","PROJECT_ROOT_IN_CONTAINER":"/var/www/server/spring-sample-h-auth","APP_ENV":"local"}
DOCKER_BUILD_LABELS=[]
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=

DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=[]
DOCKER_COMPOSE_HOST_VOLUME_CHECK=false

NGINX_CLIENT_MAX_BODY_SIZE=50M

Expand Down
4 changes: 4 additions & 0 deletions .env.java.real
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ DOCKER_COMPOSE_ENVIRONMENT={"TZ":"Asia/Seoul"}
# This goes with "docker build ... in the 'run.sh' script file", and the command always contain "HOST_IP" and "APP_ENV" above.
# docker exec -it CONTAINER_NAME cat /var/log/env_build_args.log
DOCKER_BUILD_ARGS={"DOCKER_BUILDKIT":"1","PROJECT_ROOT_IN_CONTAINER":"/var/www/server/spring-sample-h-auth","APP_ENV":"production"}
DOCKER_BUILD_LABELS=["foo=happy","bar=sad"]
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=

DOCKER_COMPOSE_REAL_SELECTIVE_VOLUMES=["./samples/spring-sample-h-auth/logs:/var/www/files"]
DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=["./shared/nginx-error-logs:/var/log/nginx"]
DOCKER_COMPOSE_HOST_VOLUME_CHECK=false

NGINX_CLIENT_MAX_BODY_SIZE=50M

Expand Down
4 changes: 3 additions & 1 deletion .env.java.real.commercial.ssl.sample
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ DOCKER_COMPOSE_ENVIRONMENT={"TZ":"Asia/Seoul"}
# This goes with "docker build ... in the 'run.sh' script file", and the command always contain "HOST_IP" and "APP_ENV" above.
# 2) ''/var/web/project/spring-sample-h-auth' is here as well
DOCKER_BUILD_ARGS={"DOCKER_BUILDKIT":"1","PROJECT_ROOT_IN_CONTAINER":"/var/www/server/spring-sample-h-auth","FILE_STORAGE_ROOT_IN_CONTAINER":"/var/www/files","JVM_XMS":"2048","JVM_XMX":"4096"}
DOCKER_BUILD_LABELS=["foo.mylabel=happy","bar.mylabel=happy"]
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=/var/www/server/spring-sample-h-auth

# 3) ''/var/web/project/spring-sample-h-auth' is here as well. The thing is you should locate 'application.properties', 'logback-spring.xml', 'yourdomain.com.jks' on the './src/main/resource' folder.
DOCKER_COMPOSE_REAL_SELECTIVE_VOLUMES=["/var/web/files/spring-sample-h-auth:/var/www/files","/var/web/project/spring-sample-h-auth/src/main/resources:/var/www/server/spring-sample-h-auth/src/main/resources"]
DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=["/var/web/files/nginx/spring-sample-h-auth/logs:/var/log/nginx"]

DOCKER_COMPOSE_HOST_VOLUME_CHECK=false

NGINX_CLIENT_MAX_BODY_SIZE=50M

Expand Down
4 changes: 4 additions & 0 deletions .env.node.local
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ GOOD_APP_HEALTH_CHECK_PATTERN=docs
# This is for environment variables for docker-compose-app-${app_env}.
DOCKER_COMPOSE_ENVIRONMENT={"MONGODB_URL":"mongodb://host.docker.internal:27017/node-boilerplate","NODE_ENV":"development"}
DOCKER_BUILD_ARGS={}
DOCKER_BUILD_LABELS=["foo=happy","bar=sad"]
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=

DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=[]
DOCKER_COMPOSE_HOST_VOLUME_CHECK=false

NGINX_CLIENT_MAX_BODY_SIZE=50M

Expand Down
5 changes: 4 additions & 1 deletion .env.php.local
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ DOCKER_COMPOSE_ENVIRONMENT={"XDEBUG_CONFIG":"idekey=IDE_DEBUG","PHP_IDE_CONFIG":
# This goes with "docker build ... in the 'run.sh' script file", and the command always contain "HOST_IP" and "APP_ENV" above.
# docker exec -it CONTAINER_NAME cat /var/log/env_build_args.log
DOCKER_BUILD_ARGS={"SAMPLE":"YAHOO","SAMPLE2":"YAHOO2"}
DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=[]
DOCKER_BUILD_LABELS=["foo=happy","bar=sad"]
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=

DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=[]
DOCKER_COMPOSE_HOST_VOLUME_CHECK=false

NGINX_CLIENT_MAX_BODY_SIZE=50M

Expand Down
5 changes: 5 additions & 0 deletions .env.php.real
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,15 @@ DOCKER_COMPOSE_ENVIRONMENT={"XDEBUG_CONFIG":"idekey=IDE_DEBUG","PHP_IDE_CONFIG":
# This goes with "docker build ... in the 'run.sh' script file", and the command always contain "HOST_IP" and "APP_ENV" above.
# docker exec -it CONTAINER_NAME cat /var/log/env_build_args.log
DOCKER_BUILD_ARGS={"SAMPLE":"YAHOO","SAMPLE2":"YAHOO2","shared_volume_group_id":"1351","shared_volume_group_name":"laravel-shared-volume-group"}
DOCKER_BUILD_LABELS=["foo=happy","bar=sad"]
# Your Git's commit SHA will be added as a label to DOCKER_BUILD_LABELS when your container is built.
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=

# In the case of "REAL," the project is not synchronized in its entirety. The source codes that are required for only production are injected.
# For SSL, the host folder is recommended to be './.docker/ssl' to be synchronized with 'docker-compose-nginx-original.yml'
DOCKER_COMPOSE_REAL_SELECTIVE_VOLUMES=["./shared/app-error-logs:/var/www/app/storage/logs","./.docker/ssl:/etc/apache2/ssl"]
DOCKER_COMPOSE_NGINX_SELECTIVE_VOLUMES=["./shared/nginx-error-logs:/var/log/nginx"]
DOCKER_COMPOSE_HOST_VOLUME_CHECK=false

NGINX_CLIENT_MAX_BODY_SIZE=50M

Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
/shared/system-logs/*
!/shared/system-logs/.gitkeep

/bin/*
!/bin/.gitkeep


**/.idea
/.env
/.env.ready.*
Expand Down
117 changes: 68 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

> One Simple Zero-Downtime Blue-Green Deployment with your Dockerfiles
Deploying web projects should be [simple, with high availability and security](https://github.com/Andrew-Kang-G/docker-blue-green-runner?tab=readme-ov-file#Quick-Guide-on-Usage).

- Use ``the latest Release version`` OR at least ``tagged versions`` for your production, NOT the latest commit of the 'main' branch.
- In production, place your project in a separate folder, not in the samples folder, as they are just examples.

## Table of Contents
- [Process Summary](#process-summary)
- [Features](#features)
- [Requirements](#requirements)
- [Quick Start with Samples](#quick-start-with-samples)
Expand All @@ -34,8 +30,7 @@ Deploying web projects should be [simple, with high availability and security](h
- [Consul](#consul)
- [USE_NGINX_RESTRICTION on .env](#use_nginx_restriction-on-env)
- [Advanced](#advanced)
- [Process Summary](#process-summary)
- [Gitlab Container Registry](#gitlab-container-registry)
- [GitLab Container Registry (Production)](#gitlab-container-registry-production)
- [Upload Image (CI/CD Server -> Git)](#upload-image-cicd-server---git)
- [Download Image (Git -> Production Server)](#download-image-git---production-server)
- [Extra Information](#extra-information)
Expand All @@ -47,6 +42,44 @@ Deploying web projects should be [simple, with high availability and security](h

---

## Process Summary

- Term Reference
- ``All`` means below is "App", "Nginx", "Consul&Registrator".
- ``(Re)Load`` means ``docker run.... OR docker-compose up``.
- ``State`` is ``Blue`` or ``Green``
- More is on [Terms](#terms)
- Load Consul & Registrator, then the App, and finally Nginx to prevent upstream errors.


```mermaid
graph TD;
A[Initialize and Set Variables] --> B[Backup All Images]
B --> C[Check the .env File Integrity]
C --> D[Build All Images]
D --> E[Create Consul Network]
E --> F{Reload Consul if Required}
F -- Yes --> G[Reload Consul]
F -- No --> H[Load Your App]
G --> H[Load Your App]
H --> I[Check App Integrity]
I --> J{Reload Nginx if Required}
J -- Yes --> K[Check Nginx Template Integrity by Running a Test Container]
J -- No --> L[Check All Containers' Health]
K --> L[Check All Containers' Health]
L --> M{Set New State Using Consul Template}
M -- Fails --> O[Run Nginx Contingency Plan]
M -- Success --> N[External Integrity Check]
O --> N[External Integrity Check]
N -- Fails --> P[Rollback App if Needed]
N -- Success --> Q["Remove the Opposite State (Blue or Green) from the Running Containers"]
P --> Q["Remove the Opposite State from the Running Containers"]
Q --> R[Clean Up Dangling Images]
R --> S[Deployment Complete]
```
![img5.png](/documents/images/img5.png)
![img6.png](documents/images/img6.png)
## Features

- **No Unpredictable Errors in Reverse Proxy and Deployment**
Expand All @@ -58,6 +91,7 @@ Deploying web projects should be [simple, with high availability and security](h

- **From Scratch**
- Docker-Blue-Green-Runner's `run.sh` script is designed to simplify deployment: "With your `.env`, project, and a single Dockerfile, simply run 'bash run.sh'." This script covers the entire process from Dockerfile build to server deployment from scratch.
- This means you can easily migrate to another server with just the files mentioned above.
- In contrast, Traefik requires the creation and gradual adjustment of various configuration files, which can introduce the types of errors mentioned above.

- Focus on zero-downtime deployment on a single machine.
Expand Down Expand Up @@ -105,10 +139,10 @@ Deploying web projects should be [simple, with high availability and security](h
| git | N/A | Manual | - |
| bash | 4.4 at least | Manual | - |
| curl | N/A | Manual | - |
| yq | 4.35.1 | Manual | Use v4.35.1 instead of the latest version. The lastest version causes a parsing error |
| yq | 4.35.1 | Auto | Use v4.35.1 instead of the latest version. The lastest version causes a parsing error |
| consul (docker image) | 1.14.11 | Auto | An error occurred due to a payload format issue while the lastest version of it was communicating with gliderlabs/registrator. |
| gliderlabs/registrator (docker image) | master | Auto | |
| nginx (docker image) | latest | Auto | Considering changing it to a certain version, but until now no issues have been detected. |
| nginx (docker image) | 1.25.4 | Auto | Considering changing it to a certain version, but until now no issues have been detected. |
| docker | 24~27 | Manual | I think too old versions could cause problems, and the lastest version v27.x causes only a warning message. |
| docker-compose | 2 | Manual | I think too old versions could cause problems, and the v2 is recommended. |

Expand Down Expand Up @@ -273,9 +307,9 @@ sudo bash run.sh
- ```shell
APP_URL=http://localhost:<--!host-port-number!-->
PROJECT_PORT=<--!common-port-number!--> OR
PROJECT_PORT=[<--!host-port-number!-->,<--!new-project-port-number!-->]
PROJECT_PORT=[<--!host-port-number!-->,<--!internal-project-port-number!-->]
```
- Additionally, the APP_URL parameter is used for 'check_availability_out_of_container' at [Structure](#Structure)
- Additionally, the `APP_URL` parameter is used for the ["External Integrity Check"](#process-summary) process.
- You can set it as https://localhost:13000 or https://your-domain:13000 for production environments. (Both configurations are acceptable)
- Moreover, the Runner parses the protocol (http or https), and if it is https, it checks for SSL certificates in the .docker/ssl directory on the host according to the following settings:
- ```shell
Expand All @@ -288,9 +322,23 @@ sudo bash run.sh
# Set this to 'real' in the .env file for production environments.
APP_ENV=real
# This path is used for both internal and external health checks.
# Note: Do not include a leading slash ("/") at the start of the path.
# Example: "api/v1/health" (correct), "/api/v1/health" (incorrect)
APP_HEALTH_CHECK_PATH=api/v1/health
# The BAD & GOOD conditions are checked using an "AND" condition.
# To ignore the "BAD_APP_HEALTH_CHECK_PATTERN", set it to a non-existing value (e.g., "###lsdladc").
BAD_APP_HEALTH_CHECK_PATTERN=DOWN
# Pattern required for a successful health check.
GOOD_APP_HEALTH_CHECK_PATTERN=UP
# The 'real' setting requires defining 'DOCKER_COMPOSE_REAL_SELECTIVE_VOLUMES'.
DOCKER_COMPOSE_REAL_SELECTIVE_VOLUMES=["/my-host/files/:/in-container/files", "/my-host/java-spring-project/src/main/resources:/in-container/java-spring-project/src/main/resources"]
# Check if the host folder or file exists
DOCKER_COMPOSE_HOST_VOLUME_CHECK=false
# If APP_ENV is set to 'local', as specified in 'docker-compose-app-local-original.yml', synchronize your entire project as follows: "HOST_ROOT_LOCATION:PROJECT_LOCATION".
# [IMPORTANT] If this is set to true, Nginx will be restarted, resulting in a short downtime.
# This option should be used when upgrading the Runner. See the "Upgrade" section below.
Expand All @@ -299,6 +347,10 @@ NGINX_RESTART=false
# Setting this to 'true' is not recommended for normal operation as it results in prolonged downtime.
CONSUL_RESTART=false
# Specify the location of the .git folder for your project here to enable tracking through container labels.
# To track, simply run `bash check-current_states.sh`.
DOCKER_BUILD_SHA_INSERT_GIT_ROOT=
# Not recommended for normal operation as it leads to a long downtime.
# If this is set to true, it entails running 'stop-all-containers.sh & remove-all-images.sh'.
# In case your project is renamed or moved to another folder, Docker may not work properly.
Expand Down Expand Up @@ -402,6 +454,8 @@ bash check-current-states.sh
[DEBUG] ! Checked which (Blue OR Green) is currently running... (Final Check) : blue_score : 130, green_score : 27, state : blue, new_state : green, state_for_emergency : blue, new_upstream : https://PROJECT_NAME:8300.
```
- The higher the score a state receives, the more likely it is to be the currently running state. So the updated App should be deployed as the non-occupied state(new_state).

- ![img6.png](documents/images/img6.png)

### Emergency
- Nginx (like when Nginx is NOT booted OR 502 error...)
Expand Down Expand Up @@ -491,44 +545,9 @@ bash check-source-integrity.sh
- **For the properties of 'environment, volumes', use .env instead of setting them on the yml.**
- Set ```USE_MY_OWN_APP_YML=true``` on .env
- ```bash run.sh```
## Process Summary
- Term Reference
- ``All`` means below is "App", "Nginx", "Consul&Registrator".
- ``(Re)Load`` means ``docker run.... OR docker-compose up``.
- ``State`` is ``Blue`` or ``Green``
- More is on [Terms](#terms)
- Load Consul & Registrator, then the App, and finally Nginx to prevent upstream errors.
```mermaid
graph TD;
A[Initialize and Set Variables] --> B[Backup All Images]
B --> C[Check the .env File Integrity]
C --> D[Build All Images]
D --> E[Create Consul Network]
E --> F{Reload Consul if Required}
F -- Yes --> G[Reload Consul]
F -- No --> H[Load Your App]
G --> H[Load Your App]
H --> I[Check App Integrity]
I --> J{Reload Nginx if Required}
J -- Yes --> K[Check Nginx Template Integrity by Running a Test Container]
J -- No --> L[Check All Containers' Health]
K --> L[Check All Containers' Health]
L --> M{Set New State Using Consul Template}
M -- Fails --> O[Run Nginx Contingency Plan]
M -- Success --> N[External Integrity Check]
O --> N[External Integrity Check]
N -- Fails --> P[Rollback App if Needed]
N -- Success --> Q["Remove the Opposite State (Blue or Green) from the Running Containers"]
P --> Q["Remove the Opposite State from the Running Containers"]
Q --> R[Clean Up Dangling Images]
R --> S[Deployment Complete]
```
## Gitlab Container Registry
## Gitlab Container Registry (Production)
### Upload Image (CI/CD Server -> Git)
- In case you run the command ``push-to-git.sh``, ``docker-blue-green-runner`` pushes one of ``Blue or Green`` images which is currently running to the address above of the Gitlab Container Registry.
Expand Down Expand Up @@ -593,4 +612,4 @@ git status # If any changes are detected, the source code may be corrupted.
docker swarm init
sudo bash run.sh
```
---
---
23 changes: 21 additions & 2 deletions apply-security.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
set -eu

source use-common.sh

check_bash_version
check_gnu_grep_installed
check_gnu_sed_installed
check_yq_installed
check_git_docker_compose_commands_exist

cache_global_vars
Expand Down Expand Up @@ -32,7 +34,24 @@ sudo chmod 750 *.sh || echo "[WARN] Running chmod 750 *.sh failed."
sudo chmod 770 *.yml || echo "[WARN] Running chmod 770 *.yml failed."
sudo chmod 740 .env.* || echo "[WARN] Running chmod 740 .env.* failed."
sudo chmod 740 .env || echo "[WARN] Running chmod 740 .env failed."
sudo chmod -R 750 bin || echo "[WARN] Running chmod 750 for the bin folder"
sudo chmod 770 .gitignore || echo "[WARN] Running chmod 770 .gitignore failed."
sudo chmod -R 770 .docker/ || echo "[WARN] Running chmod -R 770 .docker/ failed."
sudo chown -R 0:${shared_volume_group_id} .docker/ || echo "[WARN] Running chgrp ${shared_volume_group_id} .docker/ failed."
set_safe_filemode_on_app
# Check if the OS is not Darwin (macOS) before running the command
if [[ "$(uname)" != "Darwin" ]]; then
sudo chown -R 0:${shared_volume_group_id} .docker/ || echo "[WARN] Running chgrp ${shared_volume_group_id} .docker/ failed."
else
echo "[NOTICE] Skipping chown command on Darwin (macOS) platform. See the README."
fi

if [[ "$(uname)" != "Darwin" ]]; then
sudo chown -R 0:${shared_volume_group_id} bin/ || echo "[WARN] Running chgrp ${shared_volume_group_id} bin/ failed."
else
echo "[NOTICE] Skipping chown command on Darwin (macOS) platform. See the README."
fi

if [[ "$(uname)" != "Darwin" ]]; then
set_safe_filemode_on_app
else
echo "[NOTICE] Skipping chown command on Darwin (macOS) platform. See the README."
fi
Empty file added bin/.gitkeep
Empty file.
18 changes: 17 additions & 1 deletion check-current-states.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,26 @@
set -eu

source use-common.sh

check_bash_version
check_gnu_grep_installed
check_gnu_sed_installed
check_yq_installed
check_git_docker_compose_commands_exist

# Load global variables
cache_global_vars

# Define container name
container_name="${project_name}-${state}"

echo "[NOTICE] Project Name: ${project_name}"
display_emphasized_message "[NOTICE] Current State: ${state}"
display_emphasized_message "[NOTICE] Container Name: ${container_name}"


# Call the function
display_emphasized_message "$(print_git_sha_and_message "$container_name" "$docker_build_sha_insert_git_root")"

cache_global_vars
# echo "[NOTICE] All labels inside the Container $container_name"
# docker inspect -f '{{json .Config.Labels}}' "$container_name" 2>/dev/null | yq -P
Loading

0 comments on commit 812091c

Please sign in to comment.