정글에서 온 개발자
Docker registry 운영으로 더 편한 배포 본문
기존 시스템, 개선과 문제
우리회사의 레거시 배포 시스템은 zip 파일을 서버에 전달해 배포하는 방식이였다.
대략 아래와 같다.
1. `build.bat` 파일을 실행하면 ng build 와 go build 를 실행하고, build된 파일에 날짜를 붙여 zip 파일로 만든다.
2. 해당 zip 파일을 배포하고자 하는 머신으로 ftp 전송한다.
3. 옮긴 파일을 unzip 한다 (덮어쓰기)
4. 미리 설정해준 systemctl 을 이용하여 `sudo systemctl restart myservice` 명령어로 재시작한다.
4단계밖에 안 돼 보이지만, 정확한 경로에 복사하고 unzip해야하기 때문에 귀찮아서 개선해보려 한 적이 있다.
2024.11.22 - [구현 혹은 적용] - 웹앱 Delivery 자동화. Github Action - Self Hosted Runner
웹앱 Delivery 자동화. Github Action - Self Hosted Runner
도입 이유기존의 local build → zip 파일을 호스팅 서버로 ftp 전송 → 압축 풀기 → systemctl 실행 의 프로세스를 단축하는 배포 자동화를 구축하고자 함버전별 아카이빙 혹은 추후 버전 롤백을 염두
krafton-jungle-essay.tistory.com
쓰다보니 단점이 있었는데, 바로 'rollback' 이 필요한 경우였다.
운영환경에서 방금 배포한 코드에서 에러가 나니, 급하게 최근 버전으로라도 돌려달라는 요청이 있었다.
또 최근 작업은 개발 중간에 배포를 해버리면 데이터 정합성이 크게 깨질 것이 예상되어, staging 서버와 production 서버의 버전을 나눠서 가기도 했다.
github action 에서 branch별로 최신 버전을 자동 배포하도록 할 수도 있었겠지만, 설정이 복잡하고 버전이 좀 더 나눠지는 경우에 대응이 힘들 것으로 보여 다른 방법을 찾기로 했다.
기존 방식 장단점
기존 zip 방식의 장점은, zip한 날짜가 적혀있어서 문제가 생겼을 때 잘 됐던 버전 날짜 압축본만 해제하면 바로 production에 반영이 된다는 점이였다.
-> git으로 버전관리를 하고 있어서 문제가 되지 않은 시점의 버전만 알면 그때로 commit 해서 다시 배포하는 것도 마찬가지다.
또 다른 장점은, git은 버전이 많아서 배포본이 언제 있었는지 찾기 어려운 반면 zip 파일은 쌓여있는 파일 하나하나가 배포를 나타내기 때문에 알아보기 쉬웠다.
-> git에 tag를 다는 방법으로 해결할 수 있다.
단점은 물론 쓸 데 없는 용량 차지다.
왜 Docker image를 쓰기로 했나?
일단 Docker 명령어가 너무 편하다. docker를 사용하면 두단계로 단축된다.
1. local에서 Docker image build해 registry에 push
2. 배포 환경에서 docker image pull 해 run
docker-compose 파일이 있는 경로로 찾아 들어가는 수고도 bash와 systemctl 조합이면 해결할 수 있다.
그리고 궁극적으로는 kubernetis를 통한 배포 자동화도 생각하고 있었기 때문에 docker 이미지화 시켜놓으면 다음 스텝을 밟기 편할 것으로 보였다.
Docker registry
문제는 개인 프로젝트는 내 아이디로 Docker hub에 등록했는데, 회사에서는 Docker hub id를 따로 파지 않았다는 것이다.
그러나 회사에는 낭낭한 개발 서버가 있었다. docker registry도 docker image로 나와 있어서 쉽게 구성했다.
docker run -d -p 5000:5000 --restart=always --name registry registry:2
진짜 이렇게만 하면 끝이다. (방화벽 설정 등은 따로 해줘야 함)
그리고 Window에서는 Docker registry를 신뢰해줘야 한다.
배포용 makefile
DOCKER_BUILDKIT=1
REGISTRY=192.XXX.124.67:5000
FRONTEND_IMAGE=$(REGISTRY)/frontend:latest
BACKEND_IMAGE=$(REGISTRY)/backend:latest
.PHONY: help deploy build push build-frontend build-backend push-frontend push-backend
.DEFAULT_GOAL := help
deploy: ## 배포
make build
make push
build: ## 빌드
make build-frontend
make build-backend
build-frontend: ## 프론트엔드 빌드
docker build --cache-from $(FRONTEND_IMAGE) -t $(FRONTEND_IMAGE) -f ./web_src/Dockerfile ./web_src
build-backend: ## 백엔드 빌드
docker build --cache-from $(BACKEND_IMAGE) -t $(BACKEND_IMAGE) -f ./Dockerfile ./
push: ## 푸시
make push-frontend
make push-backend
push-frontend: ## 프론트엔드 푸시
docker push $(FRONTEND_IMAGE)
push-backend: ## 백엔드 푸시
docker push $(BACKEND_IMAGE)
help: ## 옵션 보기
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
| awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
make deploy를 하면 현재 버전이 registry에 build되어 바로 올라간다.
배포되는 서버
docker-compose.yml 을 다음과 같이 image 주소를 잡아주고
version: "3.8"
services:
frontend-builder:
image: ${REGISTRY}/frontend:latest
volumes:
- shared-dist:/dist
command: sh -c "cp -r web/* /dist"
backend:
image: ${REGISTRY}/backend:latest
volumes:
- shared-dist:/app/web
- ./conf.json:/app/conf.json
- ./logs:/app/logs
- ./uploads:/app/uploads
ports:
- 8090:8081
restart: always
volumes:
shared-dist:
.env 로 REGISTRY를 잡아주면 된다.
REGISTRY=xxx.xxx.xxx.xxx:5000
localhost라면 따로 insecure-registry가 필요 없지만, 다른 서버의 레지스트리를 사용할 경우, 서버에서도 해당 registry에 대한 권한 허용이 필요하다.
linux insecure-registry
sudo mkdir -p /etc/docker
sudo nano /etc/docker/daemon.json
{
"insecure-registries": ["192.XXX.XXX.67:5000"]
}
sudo systemctl restart docker 로 한번 재시작해줘야 한다.
더 나아가서 docker pull과 함께 다시 강제로 재생성 up을 하는 다음과 같은 shell script도 작성해줬다.
#!/bin/bash
set -e
echo "🔄 Pulling latest images..."
docker compose pull frontend-builder backend
echo "🚀 Starting services with updated images..."
docker compose up -d --force-recreate frontend-builder backend
echo "✅ Done!"
결과
이제 배포시에 로컬에서 `make deploy`
배포받을 서버에서 `sh deploy.sh` 만 실행하면, 해당 서버에서 최신 이미지로 업데이트가 된다.
production은 더 엄격하게 테스트 코드를 거치는 등의 과정을 거쳐 배포해야겠지만, staging의 경우나 우리 팀처럼 2명이 간단한 기능 수정한 걸 바로바로 올리고 싶을 때는 일반 zip파일을 올리는 것보다 훨씬 빠르게 할 수 있다.
추후 목표
latest 로 버전을 통일하고 있는데, 의미있는 버전의 경우 tag를 따로 달아서 관리하는 게 더 좋을 것 같다.
'구현 혹은 적용' 카테고리의 다른 글
웹앱 Delivery 자동화. Github Action - Self Hosted Runner (1) | 2024.11.22 |
---|---|
WAS를 System Service로 만들기 (0) | 2024.11.21 |
Angular로 트리구조 표현하기 (1) | 2024.07.01 |
DB로 트리구조 만들기 (조직도) (0) | 2024.07.01 |
Angular 동적 폼 만들기 (0) | 2024.06.26 |