Yeppyshiba Blog

About
coding

gitlab-runnner 를 활용한 docker 배포

9/15/2020

devcodinggitgitlabgitlab runnerdockerdeploycicd

서론

jekyll 블로그를 사용하면서 github action 에 대해서 많이 부러움을 느꼈습니다.

2434BC4257A04CAC1D

여기서는 gitlab 과 gitlab-runner (+ nexus) 를 설치하여 나도 자동적으로 빌드와 배포가 되도록 CI (Continuous Integration) / CD (Continuous Deployment) 를 구성 해보았습니다.

Basic Concept

발로 그린 diagram
발로 그린 diagram

기본 컨셉은 다음과 같습니다! 코드를 보내면 자동으로 도커 이미지를 생성하고 배포 대상 서버에서 컨테이너를 실행!

  1. gitlab 으로 코드를 커밋
  2. build
  • CI/CD (gitlab runner) 가 실행됨
  • 코드를 도커 이미지 로 빌드하고 사설 도커 저장소 (이하 nexus) 로 배포 진행
  1. deploy
  • 대상 원격지 서버로의 SSH 키 등록
  • 대상 원격지 서버에 SSH 명령어 전달 (nexus 로 특정 리비전을 가져와서 컨테이너를 실행)

POC (Proof-Of-Concept)

먼저 설치할 것들

물론 구성을 위해서 아래의 솔루션들이 필요합니다. 이 부분 설치는 별도의 내용을 참조하세요!
기본적으로 손쉬운 서버 설정을 위해서 빌드서버 / 배포서버 모두 docker engine 이 설치되어 있다고 가정합니다.
  • gitlab 설치
  • sonatype nexus3 설치

sonatype nexus3 설정

아래 문서를 참고 하여, 설치된 sonaytype nexus3 에서 docker 저장소를 설정합니다.

사내 Docker Registry 만들기 (Nexus3 기반)

nexus docker 로그인 연결을 그냥 admin 으로 진행 하는게 낫습니다.

위 블로그의 내용대로 nexus 설정에 다음과 세팅이 필요합니다.

  • realm 에 docker bearer token realm 추가 필요
  • docker-hosted 에 api v1 + 포트 추가 (8082)

gitlab-runner-network 추가

빌드서버에서 gitlab 만 네트워크를 분리하기 위하여 아래 명령어를 통해 네트워크를 추가합니다.
각 컨테이너간 통신은 hostname 으로 호출하게 됩니다.
bash
1$ sudo docker network create gitlab-runner-net
262322b083c76808fd3502b7388c36e7dca5087059bf688434a7dc7573dba103b

gitlab-runner 설정값 추가

gitlab runner 기본 설정값을 추가 합니다.

bash
1$ sudo mkdir -p /etc/srv/gitlab-runner
2$ sudo touch /etc/srv/gitlab-runner/config.toml

gitlab-runner / gitlab-dind 컨테이너 추가

gitlab runner 연결을 위해서 두가지 컨테이너를 추가합니다.

다음과 같은 프로세스로 runner 가 실행됩니다.

  1. gitlab-runner 는 runner 가 실행시 gitlab-dind 컨테이너를 실행시키는 주체 입니다.
  2. 실행된 gitlab-dind 컨테이너는 도커 이미지를 빌드를 합니다.
docker-in-docker !?
docker-in-docker !?
bash
1$ sudo docker run -d \
2--name gitlab-runner \
3--restart always \
4--network gitlab-runner-net \
5-v /srv/gitlab-runner/config.toml:/etc/gitlab-runner/config.toml \
6-e DOCKER_HOST=tcp://gitlab-dind:2375 \
7gitlab/gitlab-runner:alpine
위에서 만들어둔 외부의 config.toml 파일을 매핑시켜 줍니다.
추후 수정을 용이하게 하기 위함 입니다.
bash
1$ sudo docker run -d \
2--name gitlab-dind \
3--privileged \
4--restart always \
5--network gitlab-runner-net \
6-v /var/lib/docker \
7docker:18.09.9-dind

gitlab-dind 컨테이너 수정

추가된 nexus 는 https 가 지원되지 않아 insecure registry 로 등록이 필요합니다. gitlab-dind 컨테이너에 콘솔로 접속하여 수정을 진행합니다.
bash
1$ echo "{ \"insecure-registries\" : [\"nexus..somewhere.com:8082\"] }" > /etc/docker/daemon.json

gitlab-runner 등록

이제 gitlab runner 를 gitlab 에 연동 되도록 등록해야 합니다.

설정의 Runners 항목을 참조하여 등록 토큰 등을 설정합니다

gitlab runner token
bash
1$ sudo docker run -it --rm \
2 -v /srv/gitlab-runner/config.toml:/etc/gitlab-runner/config.toml \
3 gitlab/gitlab-runner:alpine \
4 register \
5 --executor docker \
6 --docker-image docker:18.09.9 \
7 --docker-volumes /var/run/docker.sock:/var/run/docker.sock
8[sudo] password for someone:
9Runtime platform arch=amd64 os=linux pid=6 revision=a998cacd version=13.2.2
10Running in system-mode.
11Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
12http://somewhere.com:8000/
13Please enter the gitlab-ci token for this runner:
14[gitlab-ci-token]
15Please enter the gitlab-ci description for this runner:
16[d6cfe8946db3]: Docker Runner
17Please enter the gitlab-ci tags for this runner (comma separated):
18Registering runner... succeeded runner=Jxyieb2E
19Please enter the executor: shell, ssh, virtualbox, docker+machine, custom, docker-ssh, parallels, dockerssh+machine, kubernetes, docker:
20[docker]:
21Please enter the default Docker image (e.g. ruby:2.6):
22[docker:18.09.9]:
23Runner registered successfully. Feel free to start it, but if it's running already the config should be
24automatically reloaded!

정상적으로 추가되었다면 ci 설정에서 해당 runner 가 노출되게 됩니다.

gitlab ci variables 등록

ssh 키 생성 (클라이언트)

ssh 키는 server 에 id / password 입력 없이 접속하기 위해서 생성합니다. 여기에서는 ssh private key 만 gitlab 에 저장할 예정이며, public key 는 서버로 전송할 예정입니다.

ssh-keygen 명령어로 ssh 키를 생성합니다.

bash
1$ ssh-keygen
2Generating public/private rsa key pair.
3Enter file in which to save the key (/root/.ssh/id_rsa):
4Created directory '/root/.ssh'.
5Enter passphrase (empty for no passphrase):
6Enter same passphrase again:
7Your identification has been saved in /root/.ssh/id_rsa.
8Your public key has been saved in /root/.ssh/id_rsa.pub.
9The key fingerprint is:
10d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 root@localhost
11The key's randomart image is:
12+---[RSA 2048]----+
13|.*++ o.o. |
14|.+B + oo. |
15| +++ *+. |
16| .o.Oo.+E |
17| ++B.S. |
18| o * =. |
19| + = o |
20| + = = . |
21| + o o |
22+----[SHA256]-----+

ssh-copy-id 명령어로 ssh 키를 대상 서버로 복사합니다.

bash
1$ ssh-copy-id someone@somewhere.com

ssh 연결을 확인해보면 key 없이 잘 접속 되는 것을 확인됩니다.

bash
1$ ssh someone@somewhere.com

private key 는 gitlab ci 용 변수로 담기 위해서 복사한 후 .ssh 폴더 자체를 삭제합니다.

bash
1$ cat ~/.ssh/id_rsa
2-----BEGIN OPENSSH PRIVATE KEY-----
3b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
4...
5u+Hr4KoWBWAJVdAAAAEXJvb3RANmMwNzdhYzZkZDVjAQ==
6-----END OPENSSH PRIVATE KEY-----
7$ rm -rf ~/.ssh

sudo 등록 (서버)

보안상의 이유로 배포할 서버를 접근시에는 root 가 아니라 일반 사용자로 등록했습니다.
다만 이럴 경우 일반 사용자가 docker 를 실행시킬 권한이 제한됩니다. (root 로 구동됨)
따라서 docker 명령어는 sudo 로 실행해야 하며, 이럴 경우 비밀번호 묻는 프롬프트가 나와서 ssh 명령어를 전달하는 입장에서는 제한이 됩니다.
그러하므로 visudo 로 비밀번호를 묻지 않도록 제한할 예정입니다.

root 로 visudo 를 실행하여 docker 명령어만 패스워드 묻지 않도록 허용 합니다.

1## Allow root to run any commands anywhere
2root ALL=(ALL) ALL
3someone ALL= NOPASSWD: /bin/docker

docker insecure registries 등록 (서버)

사설 docker registry 를 생성하였기 때문에 gitlab 과 배포할 서버 모두 insecure-registries 로 등록이 필요합니다.
gitlab-dind 는 이미 등록이 완료되어서 여기에서는 배포할 서버에만 등록해줍니다.

/etc/docker/daemon.json 파일을 수정해서 아래의 경로를 추가해줍니다.

json
1{
2 "insecure-registries": ["nexus.somewhere.com:8082"]
3}

등록 (gitlab)

곧 작성할 gitlab-ci.yml 파일에 쓰일 변수들이 있습니다.
yaml 파일에서 바로 정의될 변수도 있지만, 외부에서 쓰일 변수들 설정이 필요하여 gitlab ci 설정을 들어가도록 하겠습니다

설정 → CI / CD → Variables 순서대로 접근합니다.

ci variables

아래는 등록된 모습이며 각각 다음의 내용을 기술합니다.

타입설명예제
VariablesDOCKER_PRIVATE_HOST도커 컨테이너 호스트입니다. nexus3 주소를 입력합니다.nexus.somewhere.com:8082
VariablesDOCKER_PRIVATE_PASSWORDnexus 비밀번호 입니다.nexus_password
VariablesDOCKER_PRIVATE_USERnexus 아이디 입니다.admin
VariablesPROD_SERVER_IP배포할 원격 호스트입니다.deploy.com
VariablesPROD_SERVER_PORT접근할 원격 호스트 SSH 포트입니다.22
VariablesPROD_SERVER_USER접근할 원격 호스트 유저입니다.deployer
VariablesSSH_PRIVATE_KEY생성된 private key 입니다.-----BEGIN OPENSSH ... 후략

gitlab-ci.yml 파일 등록

gitlab ci 관련해서는 이 문서 를 보시고,
우선은 commit & push 시 발동하는 파이프라인을 작성하겠습니다.

해당 CI 파일은 두가지 스테이지 (build / deploy) 로 나누어져 있으며 각각 하는 역할은 다음과 같습니다.

  • build - 도커 이미지 생성
  • deploy - 원격지 서버로 배포
yaml
1image: monoless/ansible-docker:18.09.9-03
2services:
3 - name: monoless/ansible-docker:18.09.9-dind-03
4 command: ["--insecure-registry=nexus.somwwhere.com:8082"]
5stages:
6 - build
7 - deploy
8variables:
9 IMAGE_NAME: $DOCKER_PRIVATE_HOST/hello-world:$CI_PIPELINE_ID
10
11before_script:
12 - docker info
13
14cache:
15 paths:
16 - node_modules/
17build:
18 stage: build
19 script:
20 - ls -al
21 - docker container ls -a
22 - docker build . -t $IMAGE_NAME
23 - docker login -u $DOCKER_PRIVATE_USER -p $DOCKER_PRIVATE_PASSWORD $DOCKER_PRIVATE_HOST
24 - docker push $IMAGE_NAME
25 - docker images | grep 'somewhere.com'
26
27deploy-image:
28 stage: deploy
29 before_script:
30 - 'which ssh-agent || (apk update && apk add openssh-client)'
31 - eval $(ssh-agent -s)
32 - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
33 - mkdir -p ~/.ssh
34 - chmod 700 ~/.ssh
35 - ssh-keyscan -p $PROD_SERVER_PORT $PROD_SERVER_IP >> ~/.ssh/known_hosts
36 - chmod 644 ~/.ssh/known_hosts
37 script:
38 - ssh $PROD_SERVER_USER@$PROD_SERVER_IP -p$PROD_SERVER_PORT "sudo docker login \"${DOCKER_PRIVATE_HOST}\" -
39u \"${DOCKER_PRIVATE_USER}\" -p \"${DOCKER_PRIVATE_PASSWORD}\" && sudo docker pull $IMAGE_NAME && sudo docker
40stop \$(sudo docker ps -aq) && sudo docker rm \$(sudo docker ps -aq) && sudo docker run -d --restart=unlessstopped -p 5000:5000 $IMAGE_NAME"

gitlab-ci.yml 파일이 생성되면, 해당 저장소의 수정이 된 것으로 판단 자동적으로 파이프라인이 실행됩니다.

이후 정상적으로 배포된 docker image 와 원격지 서버를 확인 하였습니다.

successful build

결론

지금 작성한 gitlab-ci 코드를 통해서 지속적인 통합과 배포를 구성하였습니다.

이점으로는

  1. 코드로 손쉬운 통합이 가능합니다. (다만 gitlab-runner 에 대한 어느정도 학습이 필요합니다.)
  2. 솔직히 jenkins 보다는 쉬운거 같습니다....

아쉬운 점으로는

  1. 테스트/스테이지 환경에 대한 부분은 브렌치를 통해서 구현이 필요할 것 같습니다.
  2. 여러 서버로 배포시 대응이 필요합니다.

Relate
Stories

울펜슈타인3D 는 과연 어떻게 3d를 구현했을까요?

울펜슈타인3D 는 과연 어떻게 3d를 구현했을까요?

coding
3 years ago, 31 Views

1992년 5월 5일, 울펜슈타인 3D가 출시됩니다. 그전에도 1인칭 시점의 게임은 존재하였지만, 이 게임은 화려한 256 컬러 그래픽, 빠른 속도, 높은 프레임 레이트, 영리한 AI, 선명한 사운드 효과, 매력적인 음악을 가능하게 한 엔진으로 신선한 충격을 선사하였습니다.

Read more
jekyll 블로그 wsl2 + docker + vscode 에서 작업하기

jekyll 블로그 wsl2 + docker + vscode 에서 작업하기

coding
3 years ago, 16 Views

깃헙 블로그를 작성하기 위해서는 로컬 pc 에서 ruby 를 설치하고 jekyll 환경 구성을 해야 합니다. 오늘 포스팅을 작성할려고 했으나, windows 를 다시 깔아버려서 세팅하기가 너무 귀찮더라구요... 이번 기회에 저처럼 자주 이러저리 옮겨다니는 사람들을 위해 이번 내용을 작성하게 되었습니다.

© 2022-2023 Yeppyshiba Blog. All rights reserved.

Akita inu icons created by tulpahn - Flaticon