티스토리 뷰

도커 이미지 태깅

도커는 IMAGE ID로 이미지가 구분되지만, 이 값은 자동으로 생성되기에 의미를 알기 어렵다. 그래서 보통 Repository:[:TAG] 로 도커 이미지를 구분한다.

그런데, 도커 이미지를 태깅하다보면 한 가지 의문점이 생긴다. 먼저 태그를 붙이지 않으면 자동을 latest 태그가 붙다보니 쉘스크립트로 도커파일 빌드를 자동화해도 계속 latest가 붙은 이미지가 만들어지고 기존 이미지는 :이 되어버린다.

그렇다고 이미지를 삭제하자니 찜찜하고(사실 리파지토리를 사용하면 삭제해도 괜찮다. 퍼블릭으로는 docker hub, 프라이빗으로는 aws ecs 정도가 있겠다.)

그래서 도커 이미지에 의미있는 태그를 붙여서 버전을 관리하고 싶어졌다.

버전을 관리하고 싶어졌다..랄까?

버전 태그는 1.0.1, 1.0.2 등으로 달면 되지 않나 싶다. 이렇게 semantic versioning을 하는 것은 문제가 되지 않긴 한다. 하지만 이런 방식만을 사용한다면 사람이 하나하나 수동으로 태깅을 해야하며 그런 과정속에 HUMAN ERROR가 나기 쉽다. 또 Ci/CD 파이프라인이 있다면... 얘한테 버전을 알려줄 방법도 고민해야한다.

도커에 v1, v1.0.1, v1.0.2 등을 붙이는 것도 문제가 되는 것은 아니지만(semantic versioning) 이미지에 태깅하는 방식을 이것만 사용한다면 일일이 수동으로 태깅을 해야하니 프로세스 내에서 오류가 나기 쉽다(버전 업그레이드를 할 때 CI/CD 파이프 라인에 버전을 알려줄 수가.. 있나?)

그래서 제안하는 방식은, git repository의 HEAD의 해쉬값을 태그로 붙이는 것이다.

git HEAD의 해시값을 도커 이미지에 붙이기

git HEAD의 해시값을 도커 이미지의 태그에 붙인다면 다음과 같은 형식이라고 할 수 있다.

docker build -t recoder/websocket:9474f41ad680cff3e8ceaa27b64a955ba47d7f8f .

그리고 지금 태그 붙이는 게 최신 버전이라면, 바로 latest 태그를 붙일 수 도 있다. (물론 latest 태그를 최신 버전이라는 의미로 받아들여서는 안된다. 얘는 기본으로 사용되는 태그이기도 하고, 항상 단어 뜻 그대로 "최신"을 의미하지는 않기 때문에. 무슨 말인지 모르겠다고요? latest도 그냥 태그의 한 종류일 뿐 그 이상 그 이하도 아니라는 말입니다)

docker tag recoder/websocket:9474f41ad680cff3e8ceaa27b64a955ba47d7f8f recoder/websocket:latest

그러면 자연스레 따라오는 질문은, 어떻게 HEAD의 해시값을 가지고 오느냐? 생각보다 간단하다. 바로 git log 명령어에 여러 옵션을 주는 것이다.

git log로 git HEAD의 해시값 가져오기

$ ~/recoder$ git log -1
commit 50561e87367ff6155b18d15d7985197bc172657a (HEAD -> develop, origin/develop)
Author: jsjphone8 <jsjphone8@gamil.com>
Date:   Thu Sep 24 22:55:32 2020 +0900

git log -1 을 이용하면 위와 같이 해시값, author, date을 볼 수 있다. 하지만 우리가 붙이고 싶은 건 해시값뿐이니 git log--pretty 옵션을 사용해보자.

$ git log -1 --pretty=%H
50561e87367ff6155b18d15d7985197bc172657a

해시가 너무 길다 싶으면 --pretty=%h 옵션을 주어 짧은 버전을 사용할 수 있다(H -> h 소문자로 가면서 줄어든다는 의미)

$ git log -1 --pretty=%h
50561e8

도커 이미지 태깅 자동화

드디어, 이것을 이용하면 docker build -t의 자동화를 할 수 있다. 그동안 쉘스크립트를 통해서 자동화를 해왔기에, 쉘 스크립트에서 태깅을 추가하는 방식으로 갔다(참고로 쉘스크립트에서 명령어 실행결과를 변수에 담기위해서는, 명렁어를 $()로 감싸거나 백틱()`으로 감싸면 된다.).

아래는 실제 우리 프로젝트에서 도커 이미지 빌드 후 컨테이너를 띄우는 걸 자동화한 쉘 스크립트이다.

#!/bin/bash

branch=$1
default_branch=develop
PROJECT_DIR_PATH=/home/${USER}/recoder
NODE_SERVER_DIR_NAME=nodejs
CONTAINER_NAME=websocket

cd $PROJECT_DIR_PATH

echo "******** Step1 리모트 브랜치 업데이트 ********"
git remote update

echo "******** Step2 ${branch:=${default_branch}}로 체크아웃 후 pull********"
git checkout ${branch:=${default_branch}}
git pull origin ${branch:=${default_branc}}


echo "******** 🐋 Step3 DOCKERFILE BUILD  🐋********"
cd $NODE_SERVER_DIR_NAME
HASH=$(git log -1 --pretty=%H)
docker build -t recoder/websocket:${HASH} .

echo "******** 🐋 Step4 기존 컨테이너 죽이기 🐋 ********"
docker rm -f websocket

echo "******** 🐋 Step5 컨테이너 띄우기 🐋 ********"
docker run -d -p 3000:3000 -p 3001:9090 \
 --restart=always \
 --volume=/home/${USER}/logs:/usr/src/logs \
 --name=websocket \
 -e TZ=Asia/Seoul \
 recoder/websocket:${HASH}

echo "******** 🐋 Step6 태깅하고 ECS에 푸시하기 🐋 ********"
docker tag recoder/websocket:${HASH} ${AWS_ECS_URL}recoder/websocket:${HASH}
docker push ${AWS_ECS_URL}recoder/websocket:${HASH}

아 태깅 편안하다~

그동안 도커파일로 이미지를 계속 빌드는 하고 있었는데 매번 태깅을 따로 안하다보니 latest가 자동으로 붙고,
기존 이미지들은 고아가 되는 현상(ㅠㅠㅠ)에 굉장히 가슴아팠었다. 하지만 이제 git repository의 해시값으로 태깅을 할 수 있게 되었고 이 아이디어를 통해서 도커 이미지의 버전관리가 더 용이해졌다(심지어 여러 명이 협력할 때는 이걸 이용해서 누가 우리 서버를 박살(...)냈는지도 알아낼 수 있다.)

참고자료

Tagging Docker images the right way

댓글