본문 바로가기
프로젝트/FitTrip

[트러블슈팅] 무중단 배포간 Docker Compose 오류 해결

by 진꿈청 2024. 6. 25.

🐞 버그 설명

 

상황

FitTrip은 GCP의 GCE를 사용하여 서비스 배포를 진행했습니다.

 

FitTrip 서비스는 MSA를 목표로 하기에 각 서비스의 무중단 배포 과정이 필요했고
관련하여 작업을 자동화 시켜주는 Makefile를 작성했습니다.

 

Makefile 일부

.PHONY: up down user-update community-update chat-update state-update sig-update notification-update

all: up

up:
        docker-compose pull
        docker-compose up -d zookeeper kafka discovery-service gateway-service user-service community-service chat-service sig-service state-service notification-service

down:
        docker-compose down

user-update:
        @echo "user temp start"
        docker-compose up -d user-service-temp
        docker-compose pull user-service
        @echo "sleep 10..."
        sleep 10
        @echo "user-service update start"
        docker-compose up -d user-service
        @echo "sleep 60..."
        sleep 60

        @echo "user temp remove"
        @echo "1. find container id"
        @container_id=$$(docker ps | grep user-service-temp | grep -v 'CONTAINER' | awk '{print $$1}'); \
        echo $$container_id; \
        echo "2. remove user temp"; \
        docker exec -i $$container_id kill -15 $$(docker exec -i $$container_id lsof -i | grep java | awk 'NR==1 {print $$2}'); \
        docker rm -f $$container_id; \
        docker image prune -f

community-update:
        @echo "community temp start"
        docker-compose up -d community-service-temp
        sleep 50
        docker-compose pull community-service
        @echo "sleep 10..."
        sleep 30
        @echo "community-service update start"
        docker-compose up -d community-service
        @echo "sleep 60..."
        sleep 60

        @echo "community temp remove"
        @echo "1. find container id"
        @container_id=$$(docker ps | grep community-service-temp | grep -v 'CONTAINER' | awk '{print $$1}'); \
        echo $$container_id; \
        echo "2. remove community temp"; \
        docker exec -i $$container_id kill -15 $$(docker exec -i $$container_id lsof -i | grep java | awk 'NR==1 {print $$2}'); \
        docker rm -f $$container_id; \
        docker image prune -f

...

해당 Makefile은 GCE 로컬에서 make community-update와 같이 실행했을 때 문제 없이 다음과 같은 순서로 잘 동작했습니다.

 

 

커뮤니티 서비스 예시 절차

  1. 무중단 서비스를 위한 community-service-temp 컨테이너 구동
  2. docker-compose로 새로운 community-service 이미지 pull
  3. docker-compose up -d community-service로 새로운 이미지로 컨테이너 구동
  4. community-service-temp 서비스 컨테이너 ID 확인
  5. 컨테이너에 직접 접근하여 Spring과 관련된 Java 프로세스를 종료시킴으로 컨테이너 삭제 및 서비스 디스커버리에서 서버 DOWN
  6. 무중단 배포 성공
  7.  

하지만, Github Actions에서 똑같은 작업에 관하여 오류가 발생했고 이슈를 남기려 합니다.

 

 

발생한 버그


아래 로그처럼 GCE 로컬에서 실행시 잘 동작하던 것이 Github Actions에서 똑같이 make community-update로 실행했을 때,
오류가 발생했습니다.

 

Github Actions 오류 로그

err: [64003] Failed to execute script docker-compose
err: ERROR: for community-service  'ContainerConfig'
err: ERROR: for community-service  'ContainerConfig'
err: Traceback (most recent call last):
err:   File "docker-compose", line 3, in <module>
err:   File "compose/cli/main.py", line 81, in main
err:   File "compose/cli/main.py", line 203, in perform_command
err:   File "compose/metrics/decorator.py", line 18, in wrapper
err:   File "compose/cli/main.py", line 1186, in up
err:   File "compose/cli/main.py", line 1182, in up
err:   File "compose/project.py", line 702, in up
err:   File "compose/parallel.py", line 108, in parallel_execute
err:   File "compose/parallel.py", line 206, in producer
err:   File "compose/project.py", line 688, in do
err:   File "compose/service.py", line 581, in execute_convergence_plan
err:   File "compose/service.py", line 503, in _execute_convergence_recreate
err:   File "compose/parallel.py", line 108, in parallel_execute
err:   File "compose/parallel.py", line 206, in producer
err:   File "compose/service.py", line 496, in recreate
err:   File "compose/service.py", line 615, in recreate_container
err:   File "compose/service.py", line 334, in create_container
err:   File "compose/service.py", line 922, in _get_container_create_options
err:   File "compose/service.py", line 962, in _build_container_volume_options
err:   File "compose/service.py", line 1549, in merge_volume_bindings
err:   File "compose/service.py", line 1579, in get_container_data_volumes
err: KeyError: 'ContainerConfig'
err: make: *** [Makefile:40: community-update] Error 255

GCE와 Github Actions에서 사용한 절차 및 명령어가 완전히 똑같은데도 발생하는 해당 오류는 정말 어려웠습니다.
오류를 만나고 시도해본 방법은 다음과 같습니다.

 

시도한 방법

  1. sudo 명령어 사용
  2. Github Actions Script 대신 Run 명령어 사용
  3. makefile을 그냥 .sh 형태의 쉘 스크립트로 모듈화

 

1, 2, 3번이 근본적인 오류를 해결하기 위한 방법이 아니라는 것은 알고 있었으나,
별 다른 문제 요소를 찾을 수 없어 위 방법들을 시도하였고 역시나 오류가 해결되진 않았습니다.

 

특히, docker-compose up -d community-service-temp는 되지만,
docker-compose up -d community-service는 안되는 모순적인 문제가 발생하였습니다.

 

 

당시 올렸던 StackOverflow
https://stackoverflow.com/questions/78576791/error-with-containerconfig-in-github-actions

 

Error with ContainerConfig in GitHub Actions

I'm currently trying to deploy on Google Cloud Engine (GCE) using a Makefile and docker-compose.yml. When I execute the command make community-update on the GCE server, everything works fine. Howe...

stackoverflow.com

 

버그 해결

그렇다면 남은 것 중 유일하게 걸리는 부분은 docker-compose up -d commutniy-service로만
기존 이미지를 업데이트 하는 부분이었습니다.

 

처음부터 이 부분을 건들지 않은 이유는 이미지 자동 업데이트 및 재실행과 관련하여 아래 상황 등에서 문제가 없었기 때문입니다.

 

건들지 않은 이유

  1. GCE 내부 실행시 정상 작동
  2. 노트북 및 가상머신에서도 정상 작동

그래도 남은 가능성 및 오류 로그를 확인했을 때 가장 가능성이 큰 부분인 것 같아서,
해당 docker-compose up -d community-service 부분을 컨테이너를 아예 내리고

새롭게 띄워지도록 코드를 변경했습니다.

 

 

변경한 쉘 스크립트

#!/bin/bash

echo "community temp start"
docker-compose up -d community-service-temp
sleep 30
docker-compose pull community-service
echo "sleep 30..."
sleep 30

echo "community remove"
echo "1. find container id"
container_id=$(docker ps | grep community-service | grep -v 'CONTAINER' | awk 'NR==2 {print $1}')
echo $container_id
echo "2. remove community"
docker exec -i $container_id kill -15 $(docker exec -i $container_id lsof -i | grep java | awk 'NR==1 {print $2}')
docker rm -f $container_id

echo "community-service update start"
docker-compose up -d community-service
echo "sleep 60..."
sleep 60

echo "community temp remove"
echo "1. find container id"
container_id=$(docker ps | grep community-service-temp | grep -v 'CONTAINER' | awk '{print $1}')
echo $container_id
echo "2. remove community temp"
docker exec -i $container_id kill -15 $(docker exec -i $container_id lsof -i | grep java | awk 'NR==1 {print $2}')
docker rm -f $container_id
docker image prune -f

 

기존 방식처럼 이미지를 pull한 뒤 바로 docker-compose up -d community-service로 컨테이너를 재실행하는 방식이 아닌 컨테이너를 완전히 내리고 다시 띄우는 위 쉘 스크립트처럼 했더니 문제가 해결되었습니다.

 

의문점

 

오류는 해결되었지만 여기서 생기는 궁금증이 몇 가지가 있습니다.

 

왜 로컬에서는 실행되는 작업이 Github Actions에서는 실행이 되지 않는가?

 

가능한 경우의 수

  1. Github Actions가 러닝되는 환경의 docker-compose 버전 기준으로 명령어 동작을 해서?
  2. docker-compose 내부적으로 docker-compose up -d 명령어가 외부 요청으로 인해 실행되면 안되게 막는 경우?

이 밖에도 다른 경우의 수가 있을 수 있을 수 있을 수 있습니다만,
로컬에서는 되고 Github Actions로 했을 때는 모호한 이 오류의 원인은 정확히 모르겠습니다.

 

🙋🏻 More

원인을 찾는 과정에서 Makefile에서 쉘 스크립트로 무중단 배포 관련한 스크립트 내용을 옮겼지만,
이것이 오류의 원인이 아니었기 때문에 원래 작업했던 Makefile을 알맞게 수정한다면
정상적으로 작동이 될 것 같습니다.

 

위에 작성한 의문점들에 관해서는 앞으로 개발하면서 더 알아봐야할 것 같습니다.