GitLab Runner를 사용한 CI/CD 연동 및 자동화 테스트
목표와 환경
[최종 목표]
Docker Private Registry 환경 구축 후 TLS(SSL) 인증 및 접근제어 (htpasswd)를 적용
- HTTPS/SSL 설정
- 마지막에 간단한 FLASK 테스트를 통해 변경 후 commit 하면 CI/CD 파이프라인에서 자동으로 이미지빌드 및 푸시 잘 작동하는지 확인
[참고]
Ubuntu ARM64 버전에서의 Local GitLab 설치는 번거로울 수 있다.:
GitLab.com 사용 추천
✅ 로컬 GitLab을 직접 설치하는 것은 ARM64 환경에서 다소 번거로울 수 있음.
✅ GitLab.com에서 계정을 만들어 사용하면 빠르게 실습 가능.
시스템 아키텍처
[구성 요소]
① Docker Private Registry
- Docker 이미지를 저장하고 관리하는 자체 레지스트리.
- GitLab CI/CD가 빌드한 Docker 이미지를 푸시(push) 하고, 애플리케이션이 실행될 때 풀(pull) 해서 사용.
- htpasswd 기반 인증 및 HTTPS(SSL/TLS) 적용 가능.
② GitLab
- Git 저장소를 관리하며, CI/CD 기능을 제공.
- git push를 하면 CI/CD 파이프라인이 실행되도록 설정.
③ GitLab Runner
- GitLab에서 정의한 CI/CD 파이프라인(.gitlab-ci.yml)을 실행하는 에이전트.
- 컨테이너를 실행하고 docker build, docker push 등의 작업을 수행.
④ Docker & Docker-Compose
- 컨테이너 기반으로 애플리케이션을 실행.
- docker-compose를 사용하면 여러 개의 컨테이너(예: Flask, Nginx, Private Registry)를 한 번에 관리 가능.
⑤ 애플리케이션 (Flask)
- 실제로 실행되는 서비스. Docker 이미지로 빌드하고 실행.
작동 프로세스
[CI/CD 과정]
1. 코드 변경 (git push)
- Flask 애플리케이션 코드를 수정하고 git push 하면 GitLab의 CI/CD가 실행됨.
2. GitLab Runner 실행
- .gitlab-ci.yml에 정의된 단계별 작업을 실행.
- CI/CD 파이프라인에서 Docker 이미지 빌드 및 Private Registry로 푸시.
3. Docker 이미지 빌드
- GitLab Runner가 docker build -t myregistry.com/myapp:latest . 실행.
- 빌드된 이미지를 Private Registry로 푸시.
4. Docker Private Registry에 푸시
- docker login myregistry.com
- docker push myregistry.com/myapp:latest
5. 배포 트리거 (자동 배포)
- docker-compose pull로 최신 이미지 가져오기.
- docker-compose up -d로 애플리케이션 재시작.
6. 최종 테스트 (Flask)
- 웹 애플리케이션이 정상 동작하는지 확인.
<Docker-Compose가 설치되었다는 가정 후 시작>
1) Private Registry 설정
GitLab과 CI/CD 파이프라인이 사용할 Private Docker Registry를 설정.
기본 환경 구성
Private Registry 디렉토리 생성
mkdir -p ~/docker-registry/{data,certs,auth}
cd ~/docker-registry
Docker Compose 설정
docker-compose-registry.yml
파일 생성
sudo cat <<EOF > docker-compose-registry.yml
version: '3.3'
services:
registry:
image: registry:2
container_name: private-registry
restart: always
ports:
- "5000:5000"
volumes:
- ./data:/var/lib/registry
- ./auth:/auth
- ./certs:/certs
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: "Registry Realm"
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_HTTP_ADDR: "0.0.0.0:5000"
REGISTRY_HTTP_TLS_CERTIFICATE: "/certs/gitlab-registry.crt"
REGISTRY_HTTP_TLS_KEY: "/certs/gitlab-registry.key"
EOF
보안 설정
사용자 인증 설정
mkdir -p auth
htpasswd -c -B -b auth/htpasswd gitlab "1q2w3e4r"
chmod 644 auth/htpasswd
- 이후 docker login 할 때 이 비밀번호를 사용해야
- (GitLab CI/CD에서 $CI_REGISTRY_PASSWORD 변수로 설정 가능)
SSL 인증서 설정
Private Registry SSL 인증서 생성 (VM Host IP로 설정)
mkdir -p certs && cd certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout gitlab-registry.key \
-out gitlab-registry.crt \
-subj "/C=KR/ST=Seoul/L=Seoul/O=MyCompany/CN=192.168.1.8" \
-addext "subjectAltName = IP:192.168.1.8"
Docker 인증서 신뢰 설정
sudo mkdir -p /etc/docker/certs.d/192.168.1.8:5000
sudo cp gitlab-registry.crt /etc/docker/certs.d/192.168.1.8:5000/ca.crt
- Docker는 기본적으로 신뢰할 수 있는 CA(Certificate Authority)에서 발급한 인증서만 허용
- 하지만 지금 사용한 인증서는 Self-Signed (자가 서명) 인증서이므로, Docker가 이를 신뢰하지 않음
- 따라서, Docker 클라이언트에서 이 인증서를 신뢰하도록 등록
서비스 실행 및 설정
Registry 컨테이너 실행
cd ..
docker-compose -f docker-compose-registry.yml up -d
Docker Daemon 설정
insecure-registries
설정 (daemon.json
수정)
- Docker Daemon (자체 서명된 인증서를 사용하는 레지스트리 추가 설정)
sudo vi /etc/docker/daemon.json
# 아래처럼 변경
{
"insecure-registries": ["192.168.1.8:5000"]
}
sudo systemctl restart docker
방화벽 설정
sudo ufw allow 5000
동작 확인
Registry 상태 확인
docker ps | grep private-registry
접근 테스트
docker logout 192.168.1.8:5000
docker login 192.168.1.8:5000
curl -k -u gitlab:1q2w3e4r https://192.168.1.8:5000/v2/
2) GitLab 설치
초기화 및 환경 설정
GitLab 초기화 (필요시)
GitLab 관련 데이터, 컨테이너, 이미지, 네트워크, 볼륨 완전 삭제
sudo docker-compose down -v
sudo docker rm -f $(sudo docker ps -aq)
sudo docker rmi -f $(sudo docker images | grep 'gitlab' | awk '{print $3}')
sudo rm -rf /data/gitlab /var/opt/gitlab /etc/gitlab /var/log/gitlab ~/docker-registry/data /var/lib/docker/volumes/gitlab*
sudo docker network rm $(sudo docker network ls | grep "gitlab" | awk '{print $1}')
sudo docker volume prune -f
sudo systemctl restart docker
디렉토리 구성
영속적으로 데이터를 저장하기 위한 바인드 바운트용 디렉토리 생성
mkdir -p ~/gitlab/config ~/gitlab/logs ~/gitlab/data ~/gitlab/certs
cd ~/gitlab
SSL 인증서 설정
자체 서명된 인증서 생성
mkdir -p certs
cd certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout gitlab.key \
-out gitlab.crt \
-subj "/C=KR/ST=Seoul/L=Seoul/O=MyCompany/CN=192.168.1.8" \
-addext "subjectAltName = IP:192.168.1.8"
cd ..
인증서 권한 및 시스템 설정
sudo chmod 644 certs/gitlab.key
sudo chmod 644 certs/gitlab.crt
sudo cp ~/gitlab/certs/gitlab.crt /usr/local/share/ca-certificates/gitlab.crt
sudo update-ca-certificates
git config --global http.sslCAInfo /usr/local/share/ca-certificates/gitlab.crt
GitLab 컨테이너 설정
Docker Compose 설정
hostname
과 external_url
은 설치할 서버의 IP 또는 도메인으로 반드시 수정해야 한다.
sudo cat <<EOF > docker-compose.yml
version: '3.3'
services:
gitlab-ce-arm64v8:
container_name: 'gitlab'
image: 'yrzr/gitlab-ce-arm64v8:latest'
restart: always
ports:
- '80:80'
- '443:443' # HTTPS 포트
- '8022:22' # SSH 포트 변경 (호스트 8022 → 컨테이너 22번 포트 매핑)
volumes:
- '/var/run/docker.sock:/tmp/docker.sock:ro'
- './config:/etc/gitlab'
- './logs:/var/log/gitlab'
- './data:/var/opt/gitlab'
- './certs:/etc/gitlab/ssl' # SSL 인증서 경로
environment:
EXTERNAL_URL: "https://192.168.1.8" # GitLab이 강제로 external_url을 적용하도록 설정
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://192.168.1.8'
gitlab_rails['gitlab_shell_ssh_port'] = 8022
nginx['redirect_http_to_https'] = true
nginx['ssl_certificate'] = "/etc/gitlab/ssl/gitlab.crt"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/gitlab.key"
EOF
GitLab 실행 및 확인
docker-compose up -d
설정 확인:
sudo docker exec -it gitlab grep "external_url" /etc/gitlab/gitlab.rb
참고로, /etc/gitlab/gitlab.rb
에는 반영되지 않으며, 대신 환경 변수를 통해 실행됨.
Docker 실행 확인:
docker ps | grep gitlab
서비스 상태확인:
sudo docker exec -it gitlab gitlab-ctl status
🚨 Trouble Shooting
많은 사람들이 GitLab이 실행될 때 logrotate
나 runsvdir
관련 문제로 인해 정상적으로 부팅되지 않는 문제를 겪고 있고, 다음 수동 실행을 통해 해결했다고 말한다.
sudo systemctl start gitlab-runsvdir
# 혹은
sudo /opt/gitlab/embedded/bin/runsvdir-start &
sudo gitlab-ctl restart
브라우저에서 "고급 설정 → 계속" 선택 후 접속 가능해야 정상
(자가 서명된 인증서는 신뢰할 수 없는 인증서로 인식되므로 경고가 뜨는 것이 정상임.)
3) GitLab Runner 설치
Runner 초기 설정
디렉토리 및 권한 설정
mkdir -p ~/gitlab-runner/config
chmod -R 755 ~/gitlab-runner
chown -R $(whoami):$(whoami) ~/gitlab-runner
Docker Compose 설정
cd ~/gitlab-runner
sudo cat <<EOF > docker-compose.yml
version: '3.9'
services:
gitlab-runner:
image: 'gitlab/gitlab-runner:v16.0.2'
platform: linux/arm64
container_name: gitlab-runner
privileged: true
restart: always
volumes:
- './config:/etc/gitlab-runner'
- '/var/run/docker.sock:/var/run/docker.sock'
- '/etc/docker/certs.d:/etc/docker/certs.d' # 인증서 경로 추가
EOF
restart: always
: 따로 수동으로 Runner 실행시킬 필요 없음- → entrypoint 실행되면서 컨테이너 자동 실행
privileged: true
: docker.sock을 통해 호스트의 Docker를 직접 제어하기 위해, 권한 문제 해결
Runner 실행 및 확인
실행:
docker-compose up -d
확인:
docker ps | grep gitlab-runner
4) GitLab Runner 등록
💡 GitLab CI/CD에서 Runner는 GitLab 서버와 통신하며 파이프라인을 실행하는 역할
Runner를 등록하려면 GitLab 서버의 URL과 Runner 등록 토큰이 필요
초기 설정
GitLab 초기 패스워드 확인
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
⇒ 패스워드 저장해두기
- Xof8eKS2UKALqC8+8jFYYscDSb7HzceGimzSA67gWsI=
Runner 토큰 발급
- 브라우저 접속 후, "root/<위의 password>"로 로그인
- Gitlab Admin Area 이동 -> Runners 생성
- Run untagged jos 체크 → create runner
토큰 기억해두기
SSL 인증서 설정 (자체 서명된 인증서 사용 시)
참고 : https://gitlab-docs.infograb.net/17.5/runner/configuration/tls-self-signed.html
# 컨테이너 내부에 디렉터리 생성
docker exec -it gitlab-runner bash -c "mkdir -p /etc/gitlab-runner/certs"
# 인증서 파일을 GitLab Runner 컨테이너로 복사
docker cp /etc/docker/certs.d/192.168.1.8:5000/ca.crt gitlab-runner:/etc/docker/certs.d/192.168.1.8:5000/ca.crt
# GitLab Runner 컨테이너 내부에서 인증서 신뢰 추가
docker exec -it gitlab-runner bash -c "cp /etc/gitlab-runner/certs/gitlab.crt /usr/local/share/ca-certificates/gitlab.crt && update-ca-certificates"
# GitLab Runner 컨테이너 재시작
docker restart gitlab-runner
Runner 등록 과정
1. Runner 컨테이너 접속 및 등록 시작
docker exec -it gitlab-runner bash
gitlab-runner register
2. URL 및 토큰 입력
Enter the GitLab instance URL (for example, https://gitlab.com/):
[https://gitlab.example.com]: https://192.168.1.8
Enter the registration token:
glrt-t1_tYc1xUxpz4KB8EsRyqxi
3. Runner 설정
# GitLab Runner 설명 입력 (선택)
Enter a description for the runner:
[hostname]: gitlab-runner
# GitLab Runner 실행할 태그 입력 (선택)
Enter tags for the runner (comma-separated):
(flask,ci,docker)
# executor(실행 환경) 선택
Enter an executor: docker, docker+machine, docker-ssh, shell, ssh, virtualbox, custom, parallels, kubernetes:
docker
# 기본 docker-image 선택
Enter the default Docker image (e.g. ruby:3.0, node:14, python:3.9):
python:3.9
4. 등록 확인
gitlab-runner list
웹사이트에서도 확인 가능:
이제 GitLab CI/CD 파이프라인에서 Runner가 잡(Job)을 받아 실행할 수 있음.
5) Flask 모의 프로젝트 생성
기본 구조
/home/jinho/gitlab-flask-app/ <-- Flask 프로젝트 루트 디렉토리
│── app.py <-- Flask 메인 파일
│── requirements.txt <-- Flask 패키지 목록
│── Dockerfile <-- Flask 컨테이너 이미지 빌드 정의
│── .gitlab-ci.yml <-- GitLab CI/CD 설정 파일
└── docker-compose.yml <-- (선택) 로컬 테스트용 Docker Compose 파일
프로젝트 파일 생성
mkdir -p ~/gitlab-flask-app && cd ~/gitlab-flask-app
Flask 애플리케이션 파일 (app.py)
sudo cat <<EOF > app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Hello, GitLab CI/CD Flask!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
EOF
DockerFile 작성
sudo cat <<EOF > Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
EOF
requirements.txt 작성
echo "flask" > requirements.txt
6) CI/CD 설정
CI/CD 파이프라인 구성
.gitlab-ci.yml 작성
sudo cat <<EOF > .gitlab-ci.yml
image: docker:latest
services:
- name: docker:dind
command: ["--tls=false"]
variables:
IMAGE_NAME: "$CI_REGISTRY/gitlab-flask-app"
DOCKER_TLS_CERTDIR: "/certs"
before_script:
- mkdir -p /etc/docker/certs.d/$CI_REGISTRY
- echo "$REGISTRY_CA_CERT" > /etc/docker/certs.d/$CI_REGISTRY/ca.crt
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
stages:
- build
- deploy
build:
stage: build
script:
- |
docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
docker tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:latest
docker push $IMAGE_NAME:$CI_COMMIT_SHA
docker push $IMAGE_NAME:latest
deploy:
stage: deploy
script:
- |
docker pull $IMAGE_NAME:latest
docker stop flask-app || true
docker rm flask-app || true
docker run -d -p 5000:5000 --name flask-app $IMAGE_NAME:latest
EOF
sudo ufw allow 5050/tcp
환경변수 설정
GitLab 프로젝트 설정
- GitLab 프로젝트로 이동
- Settings → CI/CD → Variables 섹션으로 이동
- 다음 변수들 추가:
- CI_REGISTRY_USER:
gitlab
- CI_REGISTRY_PASSWORD:
1q2w3e4r
- CI_REGISTRY:
192.168.1.8:5000
- REGISTRY_CA_CERT: <인증서 정보>
sudo cat /etc/docker/certs.d/192.168.1.8:5000/ca.crt
해서 나온 전문
- CI_REGISTRY_USER:
GitLab 레포지토리 설정
레포지토리 생성
- GitLab 웹사이트 접속 (
https://192.168.1.8
) - Projects → Create new project → Blank project 선택
- 설정:
- 프로젝트 이름:
gitlab-flask-app
- Visibility:
Private
(또는Internal
) - Pick a group or namespace: root
- README 파일 생성 체크 해제
- 프로젝트 이름:
Git 토큰 설정 (PAT)
CI/CD 및 Git 인증용 토큰 생성:
- api (API 액세스 권한)
- read_repository (레포지토리 읽기 권한)
- write_repository (레포지토리 쓰기 권한)
토큰: glpat-ryLsfb6uR3ngvQE_nGuE
Git SSL 설정
sudo cp ~/gitlab/certs/gitlab.crt /etc/ssl/certs/
sudo update-ca-certificates
git config --global http.sslCAInfo /etc/ssl/certs/gitlab.crt
Git 사용자 설정
git config --global user.name "root"
git config --global user.email "gitlab_admin_573e4a@example.com"
Git 초기화 및 레포지토리 연결
cd ~/gitlab-flask-app
git init --initial-branch=main
git remote add origin https://192.168.1.8/root/gitlab-flask-app.git
코드 추가 및 푸시
git add .
git commit -m "Initial commit"
git push --set-upstream origin main
CI/CD 파이프라인 확인
GitLab → Repository → CI/CD Pipelines에서 실행 상태 확인
7) 테스트
Flask 코드 수정
@app.route('/new')
def new_route():
return "This is an updated Flask app!"
변경사항 푸시
git add .
git commit -m "Added new route"
git push origin main
🚨 Trouble Shooting
$ echo "$CI_REGISTRY_PASSWORD" | docker login 192.168.1.8:5000 -u "$CI_REGISTRY_USER" --password-stdin
time="2025-02-16T07:00:09Z" level=info msg="Error logging in to endpoint, trying next endpoint" error="Get \"https://192.168.1.8:5000/v2/\": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)"
Get "https://192.168.1.8:5000/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
Cleaning up project directory and file based variables 00:01
ERROR: Job failed: exit code 1
- https://gitlab.com/gitlab-org/gitlab-runner/-/issues/3483
- 해당 문서를 보면, 저와 같은 문제로 고생하신 분들이 많습니다.
- 해결법을 아직까지 찾지 못하신거 같습니다.
- 개인적으로 Ubuntu + Docker Private Registry + HTTPS(인증서)의 조합이 세팅에 있어서 난이도 극악이라고 느낍니다…..