🎯 GitHub Container Registry 란 무엇일까 ?
GitHub Container Registry 은 Github 에서 제공하는 Docker Hub 와 같은 기능입니다. 즉, Docker Image 를 push 해서 저장하고 pull 받아 사용할 수 있습니다. 그렇다면 왜 이번 프로젝트에서 Docker Hub 를 사용하지 않고 GitHub Container Registry 사용을 결정했을까?
이유는 다음과 같습니다.
1.DockerHub 무료 버전에서는 private Image 를 하나만 올릴 수 있다.
2.GitHub Actions 과의 통합이 쉽게 설정 가능하다.
3.Github Container Registry 의 Github 기반의 프로젝트에서 이미 관리와 CI/CD 설계가 편리하다.
자! 그러면 GitHub Container Registry 가 무엇인지 파악했으니 이를 활용한 협업 방법에 대해 설명드리겠습니다.
🎯 프론트 개발자들의 로컬 환경에서 서버를 어떻게 실행시키지 ?
백엔드 개발자들이 REST API 를 개발하면 프론트 개발자들은 연동 작업을 진행해야 합니다. 이때 협업하는 방법은 다양합니다. 직접 서버를 띄워 프론트 개발자들이 연동할 수 있지만, 백엔드 작업과 프론트 연동 작업이 병렬적으로 진행되기에는 많은 리소스가 필요합니다. (서버 변경 사항이 있으면 계속 서버를 재 배포 해야함) 물론 CI/CD 자동 배포 환경을 구축해 편리하게 작업할 수 있지만 서버를 재 배포 하는 행위 자체가 많은 비용이 발생합니다.
때문에 Docker 이미지를 만들어 GitHub Container Registry 에 push 한다면, 프론트 개발자들은 본인의 컴퓨터에서 로컬 환경에 서버를 구동 시킬 수 있습니다.
1. 전체적인 흐름
- Spring Boot 애플리케이션을 Docker 이미지로 빌드
- GitHub Container Registry에 Docker이미지를 푸시
- 프론트엔드 개발자는 프로젝트를 clone 한 뒤 docker-compose 를 실행
자 그러면 위 순서에 따라 하나하나 차례ㄷ로 설명드리겠습니다.
✅ Packages 를 사용하기 위한 토큰 생성 및 로그인
현재 진행중인 organizations 입니다. Github Packages 는 패키지 저장소입니다. 즉 GitHub Container Registry 를 이용해 Docker 이미지를 올리면 Packages 에 이미지가 저장됩니다. 이후 프론트 개발자들은 여기서 Docker Image 를 pull 받아 실행 시킬 예정입니다.
Packages 를 사용하기 위해서는 토큰을 생성해야 합니다.
https://github.com/settings/tokens/new?scopes=write:packages
GitHub · Build and ship software on a single, collaborative platform
Join the world's most widely adopted, AI-powered developer platform where millions of developers, businesses, and the largest open source community build software that advances humanity.
github.com
위 링크로 접속해 다음 권한 들을 추가해 토큰을 생성합니다.
read:packages
write:packages
delete:packages
위에서 생성한 토큰을 이용해 로그인 해야 합니다.
docker login ghcr.io -u {깃허브이름} -p {발급받은 토큰}
로그인이 성공하면 "Login Succeeded" 메시지를 확인할 수 있습니다.
✅ Dockerfile 생성 && 이미지 빌드
자, 이제 Dockerfile 을 만들어야 합니다.
# base image
FROM --platform=linux/amd64 openjdk:21-jdk-slim
# 작업 디렉토리 설정
WORKDIR /app
# 빌드된 JAR 파일을 컨테이너로 복사
COPY build/libs/pet-funeral-0.0.1-SNAPSHOT.jar app.jar
# 포트 열기
EXPOSE 8080
# 애플리케이션 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
가장 먼저 Dockerfile 를 루트 디렉토리에 만들어야 합니다. 해당 설정들을 바탕으로 Docker 이미지를 만들어 GitHub 의 Container Registry 에 푸쉬해야 합니다. (.jar 파일은 bootjar 를 실행시켜 생성합니다.)
이제 Docker 이미지를 빌드해야 합니다.
✅ docker-compose 작성
services:
db:
image: mysql:8.0
container_name: pet-db
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} # root 비밀번호만 설정
MYSQL_DATABASE: pet_service # DB 스키마 이름
ports:
- "3307:3306"
volumes:
- db-data:/var/lib/mysql
networks:
- pet-network
backend:
image: ghcr.io/pet-funeral-booking-service/pet-backend-image:v1
container_name: pet-backend
restart: always
depends_on:
- db
command: ["./wait-for-it.sh", "db:3306", "--", "java", "-jar"]
env_file:
- .env
ports:
- "8080:8080"
networks:
- pet-network
volumes:
db-data:
networks:
pet-network:
driver: bridge
docker-compose 는 여러개의 컨테이너를 정의할 수 있습니다. 저는 db 와 backend 라는 두 개의 서비스를 설정했습니다. 먼저 db 서비스에 대해 간단히 설명드리겠습니다.
image: mysql:8.0 → MySQL 8.0 이미지 사용.
container_name: pet-db → 컨테이너 이름을 pet-db로 설정.
restart: always → 컨테이너가 종료되더라도 자동 재시작.
environment → 환경 변수 설정.
${DB_PASSWORD} → .env 파일에서 DB_PASSWORD 값을 불러와 MYSQL_ROOT_PASSWORD로 설정.
MYSQL_DATABASE: pet_service → pet_service라는 데이터베이스를 자동 생성.
ports: "3307:3306"
호스트 머신의 3307 포트를 컨테이너 내부의 3306 포트(MySQL 기본 포트)와 연결.
즉, localhost:3307로 접근하면 컨테이너의 MySQL에 연결 가능.
volumes: db-data:/var/lib/mysql
MySQL 데이터를 db-data 볼륨에 저장하여 컨테이너가 삭제되어도 데이터 유지.
networks: pet-network
pet-network라는 네트워크에서 다른 컨테이너와 통신.
다음은 Git Container Registry 에서 이미지를 받아와 실행시키는 서비스에 대한 설명입니다.
image: ghcr.io/pet-funeral-booking-service/pet-backend-image:v1
GitHub Container Registry(GHCR)에서 pet-backend-image:v1을 가져와 실행.
container_name: pet-backend
컨테이너 이름을 pet-backend로 설정.
restart: always
컨테이너가 종료되더라도 자동 재시작.
depends_on: db
db 컨테이너가 먼저 실행된 후 backend가 실행됨.
command: ["./wait-for-it.sh", "db:3306", "--", "java", "-jar"]
wait-for-it.sh 스크립트를 실행하여 MySQL(db:3306)이 시작될 때까지 기다린 후 java -jar 명령 실행.
env_file: .env
.env 파일을 로드하여 환경 변수 적용.
ports: "8080:8080"
호스트의 8080 포트를 컨테이너의 8080 포트와 연결.
networks: pet-network
pet-network를 통해 db 서비스와 통신.
전체적인 동작 흐름에 대해 설명드리면 다음과 같습니다.
(1) docker-compose up 실행 시 per-network 라는 Docker 네트워크가 생성됨
(2) db 컨테이너가 pet-db 라는 이름으로 실행되며 MYSQL 이 3307 포트에서 실행됨(MySql Workbench 에서 3307 포트로 접속해서 확인 가능)
(3) .env 를 읽어 backend 와 db 에 적용한다.
(4) backend 는 MYSQL (db) 와 같은 네트워크(pet-network) 내에서 통신 가능
이제 .env 파일을 만들고 docker-compose 만 실행시키면 각자 로컬 환경에서 서버가 실행될 수 있습니다.
✅ Docker 이미지를 빌드하는 명령어
docker build -t ghcr.io/{Repository 또는 Organzation 이름}/{이미지 이름}:{태그} .
저는 Organzation 이름을 넣고 태그는 버전을 지정했습니다. (참고로 Organzation 이름이 대문자면 소문자로 작성해야 합니다.)
ex)
docker build -t ghcr.io/pet-funeral-booking-service/pet-backend-image:v1 .
✅ Docker 이미지를 push 하는 명령어
docker push ghcr.io/{organzation 이름}/{빌드한 이미지 이름}:{태그}
빌드한 이미지를 Git Container Regstry 에 푸쉬하는 명령어 입니다. 푸쉬가 완료돠면 다음과 같은 메시지가 나오고 Github 의 Packages 에서 확인할 수 있습니다.
이제 서버를 구동시키기 위해서는 Install from the command line 명령어를 입력한 후 Docker Image 를 실행시키면 됩니다!
여기까지가 백엔드 개발자들이 프론트 개발자들을 위해 Docker 이미지를 제공하는 방법이었습니다.
🎯 환경 변수 제공 방법
백엔드 서버를 만들다보면 DB 설정, OAuth 관련 토큰 등 민감한 정보들을 .env 파일로 만들어 Github 에 올리지 않고 관리하곤 합니다. 저 역시 .env 파일을 만들어 application.yml 파일에서 이를 읽어 오는 방법을 많이 사용합니다.
하지만, 이렇게 설정된 환경변수들은 위에서 제공한 Docker Image 에서 읽지 못합니다. Docker Image 에서는 .jar 파일을 복사해 실행하는 역할을 담당하지, 로컬에서 설정한 .env 환경 변수들을 읽지 못합니다. 때문에 백엔드 개발자들은 .env 파일 형식을 프론트 개발자들에게 제공하고 프론트 개발자들은 이를 직접 설정해야 합니다.
✅ git clone
가장 먼저 빌드하려는 프로젝트를 clone 해야 합니다. 이후 클론한 프로젝트 경로에 접속해 아래 명령어를 순서대로 입력해주세요.
✅ .env 파일을 생성하는 명령어 (Linux/macOs)
touch .env
✅ .env 파일을 수정하는 명령어 (Linux/macOs)
nano .env
위 명령어를 입력하고 백엔드 개발자가 제공한 .env 양식을 참고해 수정해야 합니다. 저 같은 경우 아래와 같이 수정했습니다.(.env 파일은 key=value 형식으로 작성해야 합니다.)
DB_URL=jdbc:mysql://db:3306/pet_service?serverTimezone=Asia/Seoul
DB_USERNAME=root
DB_PASSWORD={비밀번호}
여기까지 잘 설정했다면 docker-compose 를 실행하면 됩니다. 참고로 docker-compose 랑 .env 파일이랑 같은 경로에 존재해야 합니다.
✅ docker-compose 실행 명령어
docker-compose up
이제 위 명령어를 실행하면 서버가 정상적으로 실행되는 것을 확인할 수 있습니다. 그리고 만약 서버를 종료하고 싶으면 다음 명령어를 실행하면 됩니다.
✅ docker-compose 종료 명령어
docker-compose down -v
🎯 정리
정리해보면 백엔드 개발자는 docker-compose 파일을 만든 뒤, Docker Image 를 Git Container Registry 에 push 합니다. 프론트 개발자들은 docker-compose 가 포함된 프로젝트를 clone 한 뒤 .env 파일을 설정 한 뒤 docker-compose 를 실행하면 각자 로컬 환경에서 서버를 구동시킬 수 있습니다.
이 방법은 백엔드 개발자가 미리 환경을 컨테이너화하여 제공하고 프론트 엔드 개발자들이 쉽게 로컬에서 동일한 환경을 실행할 수 있는 방식입니다. 하지만 이 방식은 백엔드 개발자들이 새로운 기능을 추가하거나 수정할때 docker-build -> docker push 하는 과정이 필요하지만 Git Actions 과 같은 CI/CD 를 활용해 자동화 한다면 더 편리하게 사용할 수 있습니다.
'Devops' 카테고리의 다른 글
ElasticSearch 를 EC2 에서 실행하기 (0) | 2025.04.27 |
---|---|
[Devops] Docker Compose 를 활용한 Redis Ec2 배포 (0) | 2025.01.18 |
[Devops] Spring 과 Docker Compose 를 이용한 EC2 CI/CD 구축 (0) | 2025.01.17 |