jekyll 블로그를 사용하면서 github action 에 대해서 많이 부러움을 느꼈습니다.
여기서는 gitlab 과 gitlab-runner (+ nexus) 를 설치하여 나도 자동적으로 빌드와 배포가 되도록 CI (Continuous Integration) / CD (Continuous Deployment) 를 구성 해보았습니다.
발로 그린 diagram
기본 컨셉은 다음과 같습니다! 코드를 보내면 자동으로 도커 이미지를 생성하고 배포 대상 서버에서 컨테이너를 실행!
아래 문서를 참고 하여, 설치된 sonaytype nexus3 에서 docker 저장소를 설정합니다.
nexus docker 로그인 연결을 그냥 admin 으로 진행 하는게 낫습니다.
위 블로그의 내용대로 nexus 설정에 다음과 세팅이 필요합니다.
- realm 에 docker bearer token realm 추가 필요
- docker-hosted 에 api v1 + 포트 추가 (8082)
bash1$ sudo docker network create gitlab-runner-net262322b083c76808fd3502b7388c36e7dca5087059bf688434a7dc7573dba103b
gitlab runner 기본 설정값을 추가 합니다.
bash1$ sudo mkdir -p /etc/srv/gitlab-runner2$ sudo touch /etc/srv/gitlab-runner/config.toml
gitlab runner 연결을 위해서 두가지 컨테이너를 추가합니다.
다음과 같은 프로세스로 runner 가 실행됩니다.
docker-in-docker !?
bash1$ 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 파일을 매핑시켜 줍니다.
추후 수정을 용이하게 하기 위함 입니다.
bash1$ 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
bash1$ echo "{ \"insecure-registries\" : [\"nexus..somewhere.com:8082\"] }" > /etc/docker/daemon.json
이제 gitlab runner 를 gitlab 에 연동 되도록 등록해야 합니다.
설정의 Runners 항목을 참조하여 등록 토큰 등을 설정합니다
bash1$ 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.sock8[sudo] password for someone:9Runtime platform arch=amd64 os=linux pid=6 revision=a998cacd version=13.2.210Running 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 Runner17Please enter the gitlab-ci tags for this runner (comma separated):18Registering runner... succeeded runner=Jxyieb2E19Please 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 be24automatically reloaded!
정상적으로 추가되었다면 ci 설정에서 해당 runner 가 노출되게 됩니다.
ssh 키는 server 에 id / password 입력 없이 접속하기 위해서 생성합니다. 여기에서는 ssh private key 만 gitlab 에 저장할 예정이며, public key 는 서버로 전송할 예정입니다.
ssh-keygen 명령어로 ssh 키를 생성합니다.
bash1$ ssh-keygen2Generating 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@localhost11The 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 키를 대상 서버로 복사합니다.
bash1$ ssh-copy-id someone@somewhere.com
ssh 연결을 확인해보면 key 없이 잘 접속 되는 것을 확인됩니다.
bash1$ ssh someone@somewhere.com
private key 는 gitlab ci 용 변수로 담기 위해서 복사한 후 .ssh 폴더 자체를 삭제합니다.
bash1$ cat ~/.ssh/id_rsa2-----BEGIN OPENSSH PRIVATE KEY-----3b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn4...5u+Hr4KoWBWAJVdAAAAEXJvb3RANmMwNzdhYzZkZDVjAQ==6-----END OPENSSH PRIVATE KEY-----7$ rm -rf ~/.ssh
root 로 visudo 를 실행하여 docker 명령어만 패스워드 묻지 않도록 허용 합니다.
Plain Text1## Allow root to run any commands anywhere2root ALL=(ALL) ALL3someone ALL= NOPASSWD: /bin/docker
/etc/docker/daemon.json 파일을 수정해서 아래의 경로를 추가해줍니다.
json1{2 "insecure-registries": ["nexus.somewhere.com:8082"]3}
설정 → CI / CD → Variables 순서대로 접근합니다.
아래는 등록된 모습이며 각각 다음의 내용을 기술합니다.
타입 | 키 | 설명 | 예제 |
---|---|---|---|
Variables | DOCKER_PRIVATE_HOST | 도커 컨테이너 호스트입니다. nexus3 주소를 입력합니다. | nexus.somewhere.com:8082 |
Variables | DOCKER_PRIVATE_PASSWORD | nexus 비밀번호 입니다. | nexus_password |
Variables | DOCKER_PRIVATE_USER | nexus 아이디 입니다. | admin |
Variables | PROD_SERVER_IP | 배포할 원격 호스트입니다. | deploy.com |
Variables | PROD_SERVER_PORT | 접근할 원격 호스트 SSH 포트입니다. | 22 |
Variables | PROD_SERVER_USER | 접근할 원격 호스트 유저입니다. | deployer |
Variables | SSH_PRIVATE_KEY | 생성된 private key 입니다. | -----BEGIN OPENSSH ... 후략 |
해당 CI 파일은 두가지 스테이지 (build / deploy) 로 나누어져 있으며 각각 하는 역할은 다음과 같습니다.
yaml1image: monoless/ansible-docker:18.09.9-032services:3 - name: monoless/ansible-docker:18.09.9-dind-034 command: ["--insecure-registry=nexus.somwwhere.com:8082"]5stages:6 - build7 - deploy8variables:9 IMAGE_NAME: $DOCKER_PRIVATE_HOST/hello-world:$CI_PIPELINE_ID1011before_script:12 - docker info1314cache:15 paths:16 - node_modules/17build:18 stage: build19 script:20 - ls -al21 - docker container ls -a22 - docker build . -t $IMAGE_NAME23 - docker login -u $DOCKER_PRIVATE_USER -p $DOCKER_PRIVATE_PASSWORD $DOCKER_PRIVATE_HOST24 - docker push $IMAGE_NAME25 - docker images | grep 'somewhere.com'2627deploy-image:28 stage: deploy29 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/null33 - mkdir -p ~/.ssh34 - chmod 700 ~/.ssh35 - ssh-keyscan -p $PROD_SERVER_PORT $PROD_SERVER_IP >> ~/.ssh/known_hosts36 - chmod 644 ~/.ssh/known_hosts37 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 docker40stop \$(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 와 원격지 서버를 확인 하였습니다.
지금 작성한 gitlab-ci 코드를 통해서 지속적인 통합과 배포를 구성하였습니다.
이점으로는
아쉬운 점으로는