Currently, I have set the target group to port 80 through EC2 load balancing. The status shows as "Unhealthy", and the health check details indicate "Health checks failed with these codes: \[502\]"
. The health check is set to /actuator/health
(with dependency injection in gradle and configuration in application.properties).
This error occurred while implementing Docker
, Nginx
, and Blue-Green
deployment. The server also shows CORS
errors. Nginx
is configured to pull the image from Docker.
In the instance, I have configured docker-compose.blue.yml
, docker-compose.nginx.yml
, docker-compose.green.yml
, api.conf
, upstream.conf
, nginx.conf
, current_env.txt
, deploy.sh
, health_check.sh
, and switch.sh
.
Here are the configurations in order:
docker-compose.blue.yml
version: '3.8'
services:
api:
image: ${DOCKER_REGISTRY}/[docker-repository]:${IMAGE_TAG}
container_name: api-blue
restart: unless-stopped
environment:
- SERVER_PORT=8080
ports:
- "8001:8080"
networks:
- app-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
app-network:
external: true
docker-compose.nginx.yml
version: '3.8'
services:
nginx:
image: nginx:1.21-alpine
container_name: nginx-proxy
restart: always
ports:
- "80:80"
volumes:
- ~/app/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ~/app/nginx/conf.d:/etc/nginx/conf.d:ro
- /var/log/nginx:/var/log/nginx
networks:
- app-network
networks:
app-network:
external: true
docker-compose.green.yml
version: '3.8'
services:
api:
image: ${DOCKER_REGISTRY}/[docker-repository]:${IMAGE_TAG}
container_name: api-green
restart: unless-stopped
environment:
- SERVER_PORT=8080
ports:
- "8002:8080"
networks:
- app-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
app-network:
external: true
api.conf
server {
listen 80;
server_name [backend-server];
access_log /var/log/nginx/api-access.log;
error_log /var/log/nginx/api-error.log;
location /actuator/health {
add_header 'Access-Control-Allow-Origin' '[frontend-server]' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
proxy_pass http://app_server/api/health;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded_Proto $scheme;
proxy_connect_timeout 5s;
proxy_send_timeout 5s;
proxy_read_timeout 5s;
access_log /var/log/nginx/health-access.log;
error_log /var/log/nginx/health-error.log debug;
}
location /health/blue {
proxy_pass http://blue/api/health;
access_log off;
}
location /health/green {
proxy_pass http://green/api/health;
access_log off;
}
location / {
add_header 'Access-Control-Allow-Origin' '' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
if ( $request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://app_server;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
upstream.conf
upstream blue {
server 127.0.0.1:8001;
}
upstream green {
server 127.0.0.1:8002;
}
upstream app_server {
server 127.0.0.1:8002;
}
nginx.conf
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;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}
current_env.txt -> blue or green
deploy.sh
#!/bin/bash
source ~/app/.env
DOCKER_USERNAME=${DOCKER_USERNAME:-"tmakxmgkdntn"}
IMAGE_TAG=$1
APP_NAME=${2:-"[docker-repository]"}
ENV_FILE=~/app/scripts/current_env.txt
if [ ! -f "$ENV_FILE" ]; then
echo "blue" > "$ENV_FILE"
fi
BLUE_RUNNING=$(docker ps | grep api-blue | wc -l)
GREEN_RUNNING=$(docker ps | grep api-green | wc -l)
if [ "$BLUE_RUNNING" -eq 1 ] && [ "$GREEN_RUNNING" -eq 0 ]; then
echo "blue" > "$ENV_FILE"
elif [ "$BLUE_RUNNING" -eq 0 ] && [ "$GREEN_RUNNING" -eq 1 ]; then
echo "green" > "$ENV_FILE"
elif [ "$BLUE_RUNNING" -eq 0 ] && [ "$GREEN_RUNNING" -eq 0 ]; then
echo "blue" > "$ENV_FILE"
fi
CURRENT_ENV=$(cat "$ENV_FILE")
DEPLOY_ENV=$([ "$CURRENT_ENV" == "blue" ] && echo "green" || echo "blue")
echo "Current environment: $CURRENT_ENV"
echo "Deploying to: $DEPLOY_ENV"
echo "Using image: $DOCKER_USERNAME/$APP_NAME:$IMAGE_TAG"
echo "Pulling Docker image: $DOCKER_USERNAME/$APP_NAME:$IMAGE_TAG"
if docker pull $DOCKER_USERNAME/$APP_NAME:$IMAGE_TAG; then
docker images | grep $IMAGE_TAG
else
exit 1
fi
export DOCKER_REGISTRY=$DOCKER_USERNAME
export IMAGE_TAG=$IMAGE_TAG
echo "Starting service in $DEPLOY_ENV environment..."
cd ~/app/$DEPLOY_ENV
docker-compose -f docker-compose.$DEPLOY_ENV.yml down --remove-orphans
docker-compose -f docker-compose.$DEPLOY_ENV.yml up -d
if [ $? -ne 0 ]; then
exit 1
fi
echo "Waiting for service to be healthy..."
~/app/scripts/health_check.sh $DEPLOY_ENV
if [ $? -ne 0 ]; then
echo "Health check failed. Rolling back..."
docker-compose -f docker-compose.$DEPLOY_ENV.yml down
exit 1
fi
echo "Switching traffic to $DEPLOY_ENV environment..."
~/app/scripts/switch.sh $DEPLOY_ENV
if [ $? -ne 0 ]; then
echo "Traffic switch failed. Rolling back..."
exit 1
fi
echo $DEPLOY_ENV > ~/app/scripts/current_env.txt
9. health_check.sh
#!/bin/bash
ENV=$1
MAX_RETRIES=30
RETRY_INTERVAL=2
PORT=$([ "$ENV" == "blue" ] && echo "8001" || echo "8002")
ENDPOINT="http://localhost:$PORT/actuator/health"
for i in $(seq 1 $MAX_RETRIES); do
RESPONSE=$(curl -s -w "%{http_code}" $ENDPOINT)
HTTP_CODE=$(echo "$RESPONSE" | tail -c 4)
HTTP_BODY=$(echo "$RESPONSE" | head -c -4)
if [ "$HTTP_CODE" == "200" ]; then
if echo "$HTTP_BODY" | grep -qE '"status":"UP"|"UP"'; then
exit 0
fi
fi
sleep $RETRY_INTERVAL
done
exit 1
health_check.sh
#!/bin/bash
ENV=$1
MAX_RETRIES=30
RETRY_INTERVAL=2
PORT=$([ "$ENV" == "blue" ] && echo "8001" || echo "8002")
ENDPOINT="http://localhost:$PORT/actuator/health"
for i in $(seq 1 $MAX_RETRIES); do
RESPONSE=$(curl -s -w "%{http_code}" $ENDPOINT)
HTTP_CODE=$(echo "$RESPONSE" | tail -c 4)
HTTP_BODY=$(echo "$RESPONSE" | head -c -4)
if [ "$HTTP_CODE" == "200" ]; then
if echo "$HTTP_BODY" | grep -qE '"status":"UP"|"UP"'; then
exit 0
fi
fi
sleep $RETRY_INTERVAL
done
exit 1
switch.sh
#!/bin/bash
NEW_ENV=$1
NGINX_CONF_PATH=~/app/nginx/conf.d/upstream.conf
echo "Switching traffic to $NEW_ENV environment..."
sed -i "s/server 127.0.0.1:.*/server 127.0.0.1:$([ "$NEW_ENV" == "blue" ] && echo "8001" || echo "8002");/" "$NGINX_CONF_PATH"
docker exec nginx-proxy nginx -t
if [ $? -eq 0 ]; then
echo "Nginx configuration test passed. Reloading Nginx..."
docker exec nginx-proxy nginx -s reload
echo "Traffic switched to $NEW_ENV environment."
else
echo "Nginx configuration test failed. Rolling back..."
exit 1
fi
When I check directly inside the Docker container using curl, everything works fine. However, since the status is still unhealthy, I believe there is an issue with my Nginx configuration. Could you help me identify the problem or suggest something I should study to resolve this issue? I’m a beginner, but I’m willing to put in the effort.
If any additional code is needed, please let me know. thanks..