- 서비스가 작업과 연결되는 방법
- 서비스의 상태 체크 작동 방식
- 서비스 이미지에서 제공되는 소프트웨어 사용
.gitlab-ci.yml
파일에services
정의하기- 서비스에 액세스
- 서비스에 CI/CD 변수 전달하기
services
를 위한 사용 가능한 설정- 동일 이미지에서 여러 서비스 시작하기
- 서비스를 위한 명령 설정
docker run
(Docker-in-Docker)과 함께services
사용하기- Docker 통합 작동 방식
- 서비스 컨테이너 로그 캡처
- 작업 로컬에서 디버깅
- 서비스 컨테이너 사용 시 보안
- 공유된 /builds 디렉터리
서비스
CI/CD를 구성할 때 작업이 실행되는 컨테이너를 생성하는데 사용되는 이미지를 지정합니다. 이 이미지를 지정하려면 image
키워드를 사용합니다.
services
키워드를 사용하여 추가 이미지를 지정할 수 있습니다. 이 추가 이미지는 다른 컨테이너를 생성하여 첫 번째 컨테이너에서 사용할 수 있습니다. 두 컨테이너는 서로에게 액세스하고 작업을 실행할 때 통신할 수 있습니다.
서비스 이미지는 모든 애플리케이션을 실행할 수 있지만, 가장 흔한 사용 사례는 데이터베이스 컨테이너를 실행하는 것입니다. 예를 들어:
기존 이미지를 사용하여 추가 컨테이너를 실행하는 것이 프로젝트를 빌드할 때마다 mysql
을 설치하는 것보다 더 쉽고 빠릅니다.
데이터베이스 서비스에만 국한되지는 않습니다. .gitlab-ci.yml
에 필요한 만큼 많은 서비스를 추가하거나 config.toml
을 매뉴얼으로 수정할 수 있습니다. Docker Hub에서 찾을 수 있는 이미지나 사설 컨테이너 레지스트리에서 찾을 수 있는 이미지를 서비스로 사용할 수 있습니다.
서비스는 CI 컨테이너 자체와 동일한 DNS 서버, 검색 도메인 및 추가 호스트를 상속합니다.
서비스가 작업과 연결되는 방법
컨테이너 링크 작동 방식을 더 잘 이해하려면 컨테이너를 함께 링크하는 것을 읽어보세요.
예를 들어 애플리케이션에 mysql
을 서비스로 추가하면 이미지가 작업 컨테이너에 연결된 컨테이너를 생성하는 데 사용됩니다.
MySQL을 위한 서비스 컨테이너는 호스트 이름 mysql
로 접근할 수 있습니다. 데이터베이스 서비스에 액세스하려면 소켓이나 localhost
대신 mysql
이라는 호스트에 연결하세요. 서비스에 액세스하는 방법에서 자세한 내용을 확인하세요.
서비스의 상태 체크 작동 방식
서비스는 네트워크에 접근 가능한 추가 기능을 제공하도록 설계되었습니다. 이것은 MySQL과 같은 데이터베이스나 Redis, 심지어 Docker-in-Docker를 사용할 수 있도록 합니다. CI/CD 작업을 진행하는 데 필요한 거의 모든 것이며 네트워크로 액세스될 수 있습니다.
이를 확실하게 하기 위해 러너는:
- 컨테이너에서 기본적으로 노출된 포트를 확인합니다.
- 이러한 포트에 액세스 가능할 때까지 기다리는 특수 컨테이너를 시작합니다.
두 번째 확인 단계가 실패하면 경고 메시지를 출력합니다: *** WARNING: Service XYZ probably didn't start properly
. 이 문제는 다음과 같은 이유로 발생할 수 있습니다:
- 서비스에서 열린 포트가 없습니다.
- 서비스가 제한 시간 내에 제대로 시작되지 않았고 포트가 응답하지 않습니다.
대부분의 경우 작업에 영향을 미치지만, 경고가 출력되었더라도 작업이 성공할 수 있는 상황이 있을 수 있습니다. 예를 들어:
- 경고가 발생한 후 잠시 후에 서비스가 시작되었고, 작업이 처음부터 연결된 서비스를 사용하지 않는 경우입니다. 이 경우 작업이 서비스에 액세스해야 할 때 이미 서비스가 대기 중이었을 수 있습니다.
- 서비스 컨테이너가 네트워킹 서비스를 제공하지 않지만 작업 디렉터리(모든 서비스는 작업 디렉터리를
/builds
아래의 볼륨으로 장착함)에서 작업을 수행합니다. 이 경우 서비스는 작업을 수행하며 작업이 연결을 시도하지 않기 때문에 실패하지 않습니다.
서비스가 성공적으로 시작되면, 해당 서비스는 before_script
가 실행되기 전에 시작됩니다. 따라서 before_script
에서 서비스를 쿼리할 수 있습니다.
작업이 실패하더라도 서비스는 작업이 끝나면 중지됩니다.
서비스 이미지에서 제공되는 소프트웨어 사용
services
를 지정하면 네트워크에 접근 가능한 서비스를 제공합니다. 데이터베이스가 그러한 서비스의 가장 간단한 예입니다.
서비스 기능은 정의된 services
이미지에서 작업의 컨테이너로 소프트웨어를 추가하지 않습니다.
예를 들어, 작업의 services
를 다음과 같이 정의하는 경우 php
, node
또는 go
명령어가 스크립트에서 사용 가능하지 않으며 작업은 실패합니다:
job:
services:
- php:7
- node:latest
- golang:1.10
image: alpine:3.7
script:
- php -v
- node -v
- go version
스크립트에서 php
, node
및 go
를 사용해야 하는 경우 다음 중 하나를 해야 합니다:
- 모든 필요한 도구가 포함된 기존 Docker 이미지를 선택합니다.
- 모든 필요한 도구가 포함된 사용자 정의 Docker 이미지를 만들고 작업에 사용합니다.
.gitlab-ci.yml
파일에 services
정의하기
또한 각 작업에 대해 다른 이미지와 서비스를 정의하는 것이 가능합니다:
default:
before_script:
- bundle install
test:2.6:
image: ruby:2.6
services:
- postgres:11.7
script:
- bundle exec rake spec
test:2.7:
image: ruby:2.7
services:
- postgres:12.2
script:
- bundle exec rake spec
또는 image
와 services
에 대해 확장된 구성 옵션을 전달할 수 있습니다:
default:
image:
name: ruby:2.6
entrypoint: ["/bin/bash"]
services:
- name: my-postgres:11.7
alias: db-postgres
entrypoint: ["/usr/local/bin/db-postgres"]
command: ["start"]
before_script:
- bundle install
test:
script:
- bundle exec rake spec
서비스에 액세스
예를 들어, 애플리케이션과 API 통합을 테스트하기 위해 Wordpress 인스턴스가 필요하다고 가정해봅시다. 그런 경우 .gitlab-ci.yml
파일에서 tutum/wordpress
이미지를 사용할 수 있습니다:
services:
- tutum/wordpress:latest
만약 서비스에 대한 별칭을 지정하지 않는 경우, 작업이 실행되면 tutum/wordpress
가 시작됩니다. 빌드 컨테이너에서 두 가지 호스트 이름을 사용하여 액세스할 수 있습니다:
tutum-wordpress
tutum__wordpress
밑줄이 포함된 호스트 이름은 RFC 유효하지 않으며 제3자 애플리케이션에서 문제를 일으킬 수 있습니다.
서비스의 기본 별칭은 이미지 이름에서 다음과 같은 규칙을 따라 생성됩니다:
- 콜론(
:
) 이후의 모든 것을 제거합니다. - 슬래시(
/
)는 두 개의 언더스코어(__
)로 대체하고 기본 별칭이 생성됩니다. - 슬래시(
/
)는 하이픈(-
)으로 대체하고 보조 별칭이 생성됩니다 (GitLab Runner v1.1.0 이상이 필요함).
기본 동작을 재정의하려면 서비스 별칭을 지정할 수 있습니다.
서비스 연결
외부 API가 자체 데이터베이스와 통신해야 하는 엔드투엔드 테스트와 같이 복잡한 작업에서 상호 종속적인 서비스를 사용할 수 있습니다.
예를 들어, API가 데이터베이스가 필요한 프론트엔드 애플리케이션의 엔드투엔드 테스트의 경우:
end-to-end-tests:
image: node:latest
services:
- name: selenium/standalone-firefox:${FIREFOX_VERSION}
alias: firefox
- name: registry.gitlab.com/organization/private-api:latest
alias: backend-api
- postgres:14.3
variables:
FF_NETWORK_PER_BUILD: 1
POSTGRES_PASSWORD: supersecretpassword
BACKEND_POSTGRES_HOST: postgres
script:
- npm install
- npm test
이 솔루션이 작동하려면 각 작업에 대한 새로운 네트워크를 생성하는 네트워킹 모드를 사용해야 합니다.
서비스에 CI/CD 변수 전달하기
당신은 또한 .gitlab-ci.yml
파일 내에서 Docker images
및 services
를 직접적으로 세밀하게 조정하기 위해 사용자 지정 CI/CD 변수를 전달할 수 있습니다.
더 많은 정보를 원하시면 .gitlab-ci.yml
로 정의된 변수를 읽어보세요.
# 다음 변수들은 자동으로 Postgres 컨테이너 및 Ruby 컨테이너로 전달되며 각각에서 사용할 수 있습니다.
variables:
HTTPS_PROXY: "https://10.1.1.1:8090"
HTTP_PROXY: "https://10.1.1.1:8090"
POSTGRES_DB: "my_custom_db"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "example"
PGDATA: "/var/lib/postgresql/data"
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --data-checksums"
default:
services:
- name: postgres:11.7
alias: db
entrypoint: ["docker-entrypoint.sh"]
command: ["postgres"]
image:
name: ruby:2.6
entrypoint: ["/bin/bash"]
before_script:
- bundle install
test:
script:
- bundle exec rake spec
services
를 위한 사용 가능한 설정
- GitLab 및 GitLab Runner 9.4에서 도입되었습니다.
설정 | 필요 여부 | GitLab 버전 | 설명 |
---|---|---|---|
name
| 다른 옵션과 함께 사용될 때 필수 | 9.4 | 사용할 이미지의 전체 이름. 전체 이미지 이름에 레지스트리 호스트명이 포함되어 있는 경우, alias 옵션을 사용하여 더 짧은 서비스 액세스 이름을 정의하세요. 더 많은 정보는 서비스 액세스를 참조하세요.
|
entrypoint
| 아니요 | 9.4 | 컨테이너의 진입점으로 실행할 명령 또는 스크립트입니다. 이것은 컨테이너를 생성할 때 Docker --entrypoint 옵션으로 변환됩니다. 구문은 Dockerfile 의 ENTRYPOINT 지시문과 유사하며, 각 쉘 토큰은 배열에서 각각의 별도 문자열입니다.
|
command
| 아니요 | 9.4 | 컨테이너의 명령 또는 스크립트입니다. 이미지 이름 뒤에 전달되는 인수로 Docker에 전달됩니다. 구문은 Dockerfile 의 CMD 지시문과 유사하며, 각 쉘 토큰은 배열에서 각각의 별도 문자열입니다.
|
alias (1)
| 아니요 | 9.4 | 작업 컨테이너에서 서비스에 액세스하는 데 사용할 수 있는 추가 별칭입니다. 자세한 내용은 서비스 액세스를 읽어보세요. |
variables (2)
| 아니요 | 14.5 | 서비스에 전용으로 전달되는 추가 환경 변수입니다. 구문은 작업 변수와 동일합니다. 서비스 변수는 자기 자신을 참조할 수 없습니다. |
(1) 쿠버네티스 실행자의 별칭 지원은 GitLab Runner 12.8에서 도입되었으며, 1.7 이상 버전의 쿠버네티스에서만 사용할 수 있습니다.
(2) 도커 및 쿠버네티스 실행자의 서비스 변수 지원은 GitLab Runner 14.8에서 도입되었습니다.
동일 이미지에서 여러 서비스 시작하기
- GitLab 및 GitLab Runner 9.4에서 도입되었습니다. 확장된 구성 옵션에 대해 더 읽어보세요.
새로운 확장된 Docker 구성 옵션 이전에, 다음 구성은 제대로 작동하지 않았습니다.
services:
- mysql:latest
- mysql:latest
러너(runner)는 mysql:latest
이미지를 사용하는 두 개의 컨테이너를 시작했으나, 둘 다 mysql
별칭으로 작업 컨테이너에 추가되어 기본 호스트명 네이밍을 기반으로 한 서비스가 하나는 액세스할 수 없는 상태로 끝납니다.
새로운 확장된 Docker 구성 옵션 이후, 위 예제는 다음과 같이 보일 것입니다:
services:
- name: mysql:latest
alias: mysql-1
- name: mysql:latest
alias: mysql-2
러너(runner)는 여전히 mysql:latest
이미지를 사용하여 두 개의 컨테이너를 시작하지만, 이제 각각이 .gitlab-ci.yml
파일에서 구성된 별칭으로 액세스할 수 있습니다.
서비스를 위한 명령 설정
- GitLab 및 GitLab Runner 9.4에서 도입되었습니다. 확장된 구성 옵션에 대해 더 읽어보세요.
예를 들어 super/sql:latest
이미지에 SQL 데이터베이스가 들어있다고 가정해봅시다. 이것을 작업의 서비스로 사용하고자 합니다. 또한, 이 이미지가 컨테이너를 시작할 때 데이터베이스 프로세스를 시작하지 않는다고 가정해봅시다. 사용자는 매뉴얼으로 /usr/bin/super-sql run
을 데이터베이스를 시작하기 위해 사용해야 합니다.
새로운 확장된 Docker 구성 옵션 이전에는 다음을 해야합니다:
-
super/sql:latest
이미지를 기반으로 자체 이미지를 만듭니다. - 기본 명령을 추가합니다.
-
작업의 구성에서 그 이미지를 사용합니다.
-
my-super-sql:latest
이미지의 Dockerfile:FROM super/sql:latest CMD ["/usr/bin/super-sql", "run"]
-
.gitlab-ci.yml
파일의 작업에서:services: - my-super-sql:latest
-
새로운 확장된 Docker 구성 옵션 이후, 다음과 같이 .gitlab-ci.yml
파일에서command
를 설정할 수 있습니다:
services:
- name: super/sql:latest
command: ["/usr/bin/super-sql", "run"]
command
의 구문은 Dockerfile CMD
와 유사합니다.
docker run
(Docker-in-Docker)과 함께 services
사용하기
docker run
으로 시작된 컨테이너는 GitLab이 제공하는 서비스에 연결할 수도 있습니다.
서비스를 부팅하는 것이 소모적이거나 시간이 많이 걸리는 경우, 다른 클라이언트 환경에서 테스트를 실행하면서 테스트된 서비스를 한 번만 부팅할 수 있습니다.
access-service:
stage: build
image: docker:20.10.16
services:
- docker:dind # docker run에 필요함
- tutum/wordpress:latest
variables:
FF_NETWORK_PER_BUILD: "true" # 컨테이너 간 네트워킹 활성화
script: |
docker run --rm --name curl \
--volume "$(pwd)":"$(pwd)" \
--workdir "$(pwd)" \
--network=host \
curlimages/curl:7.74.0 curl "http://tutum-wordpress"
이 솔루션이 작동하려면, 다음을 해야합니다:
- 작업마다 새 네트워크를 생성하는 네트워킹 모드를 사용합니다.
-
Docker 소켓 바인딩을 사용하지 않습니다. 반드시 사용해야 한다면, 위의 예시에서
host
대신에 이 작업용으로 생성된 동적 네트워크 이름을 사용하세요.
Docker 통합 작동 방식
아래는 작업 중에 Docker가 수행하는 단계의 고수준 개요입니다.
- 어떤 서비스 컨테이너도 생성합니다:
mysql
,postgresql
,mongodb
,redis
. -
config.toml
및 빌드 이미지 (ruby:2.6
예제와 같이)의Dockerfile
에서 정의된 모든 볼륨을 저장하기 위한 캐시 컨테이너를 생성합니다. - 빌드 컨테이너를 생성하고 모든 서비스 컨테이너를 빌드 컨테이너에 연결합니다.
- 빌드 컨테이너를 시작하고 작업 스크립트를 컨테이너로 보냅니다.
- 작업 스크립트 실행
- 코드를 다음 위치에 체크아웃합니다.
/builds/group-name/project-name/
. -
.gitlab-ci.yml
에 정의된 단계를 실행합니다. - 빌드 스크립트의 종료 상태를 확인합니다.
- 빌드 컨테이너 및 생성된 모든 서비스 컨테이너를 제거합니다.
서비스 컨테이너 로그 캡처
서비스 컨테이너에서 실행 중인 응용 프로그램에서 생성된 로그는 후속 검사 및 디버깅을 위해 캡처할 수 있습니다. 서비스 컨테이너가 성공적으로 시작되었지만 예상대로 작동하지 않아 작업 실패로 이어질 때 서비스 컨테이너의 로그를 확인할 수 있습니다. 이러한 로그는 컨테이너 내에서 서비스의 누락 또는 잘못된 구성을 나타낼 수 있습니다.
CI_DEBUG_SERVICES
는 서비스 컨테이너 로그를 캡처하는데 저장 및 성능에 영향을 미치므로 서비스 컨테이너가 활발하게 디버깅되고 있을 때만 활성화해야 합니다.
서비스 로깅을 활성화하려면 프로젝트의 .gitlab-ci.yml
파일에 CI_DEBUG_SERVICES
변수를 추가하십시오.
variables:
CI_DEBUG_SERVICES: "true"
허용되는 값은:
- 활성화:
TRUE
,true
,True
- 비활성화:
FALSE
,false
,False
기타 값은 오류 메시지를 유발하고 결과적으로 기능을 비활성화합니다.
활성화되면 모든 서비스 컨테이너의 로그가 캡처되고 다른 로그와 동시에 작업 추적 로그로 스트리밍됩니다. 각 컨테이너의 로그는 컨테이너의 별칭으로 접두어가 붙은 채로 표시되며 다른 색상으로 표시됩니다.
CI_DEBUG_SERVICES
를 활성화하면 마스킹된 변수가 공개될 수 있습니다. CI_DEBUG_SERVICES
가 활성화되면 서비스 컨테이너 로그와 CI 작업의 로그가 작업 추적 로그로 동시에 스트리밍되어 서비스 컨테이너 로그가 작업의 마스킹된 로그 내부에 삽입될 수 있습니다. 이로 인해 변수 마스킹 메커니즘이 방해되고 마스킹된 변수가 공개될 수 있습니다.CI/CD 변수 마스킹 참조
작업 로컬에서 디버깅
다음 명령은 루트 권한 없이 실행됩니다. 사용자 계정으로 Docker를 실행할 수 있어야 합니다.
먼저 build_script
라는 파일을 만들어 시작하십시오:
cat <<EOF > build_script
git clone https://gitlab.com/gitlab-org/gitlab-runner.git /builds/gitlab-org/gitlab-runner
cd /builds/gitlab-org/gitlab-runner
make runner-bin-host
EOF
여기서 Makefile을 포함하는 GitLab Runner 리포지터리를 예제로 사용하며, make
를 실행하여 Makefile에 정의된 대상이 실행됩니다. make runner-bin-host
대신 프로젝트에 특정한 명령을 실행할 수 있습니다.
그런 다음 서비스 컨테이너를 만듭니다:
docker run -d --name service-redis redis:latest
이전 명령은 최신 Redis 이미지를 사용하여 service-redis
라는 서비스 컨테이너를 만듭니다. 서비스 컨테이너는 백그라운드에서 실행됩니다(-d
).
마지막으로 앞서 만든 build_script
파일을 실행하여 빌드 컨테이너를 만듭니다:
docker run --name build -i --link=service-redis:redis golang:latest /bin/bash < build_script
위 명령은 golang:latest
이미지에서 생성된 build
라는 컨테이너를 만들고 하나의 서비스를 연결합니다. build_script
는 stdin
을 통해 파이프되며 이를 통해 build
컨테이너에서 build_script
를 실행하는 bash 인터프리터로 전달됩니다.
테스트를 마치고 더 이상 컨테이너가 필요하지 않으면 다음과 같이 제거할 수 있습니다:
docker rm -f -v build service-redis
이 명령은 강제로(-f
) build
컨테이너와 서비스 컨테이너, 그리고 컨테이너 생성 시 생성된 모든 볼륨(-v
)을 제거합니다.
서비스 컨테이너 사용 시 보안
Docker 권한 부여 모드는 서비스에 적용됩니다. 이는 서비스 이미지 컨테이너가 호스트 시스템에 액세스할 수 있다는 것을 의미합니다. 신뢰할 수 있는 소스에서만 컨테이너 이미지를 사용해야 합니다.
공유된 /builds 디렉터리
빌드 디렉터리는 볼륨으로 /builds
아래에 마운트되어 있으며 작업과 서비스 사이에서 공유됩니다. 작업은 서비스가 실행된 후에 프로젝트를 /builds/$CI_PROJECT_PATH
로 체크아웃합니다. 결과적으로 서비스가 프로젝트의 파일이 필요하거나 해당 디렉터리에 파일을 놓아서 아티팩트로서 사용하려면 해당 디렉터리가 존재하고 $CI_COMMIT_SHA
가 체크아웃된 상태여야 할 수 있습니다. 작업이 체크아웃 프로세스를 완료하기 전에 만든 변경 사항은 체크아웃 프로세스에 의해 제거됩니다.