추석 휴식 기간을 거치고 다시 키보드를 두들기려고 한다. 최근 백엔드 서버 스크립트를 작성하면서 계속 로컬 환경에서 작업을 하다보니 프론트엔드 담당 친구가 계속 백엔드 서버에 접근하지 못하는 문제가 발생했다. 그렇다고 계속 백엔드를 만지면서 늘 해왔던 것 처럼 SSH를 이용하여 명령을 치고 있을 수는 없는 법이다.

원래는 아래와 같이 명령을 쳐줘야 했다.

git clone [GIT]
npm install
ps -aux
kill -9 [PID]
nohup node app.js > apisv.log &

git clone으로 프로젝트 폴더를 다운로드하고 ps -aux 로 계속 PID를 찾아서 기존 프로세스를 종료하고 새로운 백그라운드 프로세스를 생성해야만 했다. 어렵진 않으나 번거로운 과정이다.

이를 해결해줄 수 있는 방법이 CI/CD라고 해서 조금 찾아보았다. 공부한지 하루 된 상태에서 글을 작성하는 것이므로 아래 내용은 무시하여도 좋다. 내가 이해한 바이다.

CI/CD

CI/CD란 Continuous Integration/Continuous Delivery라고 하여 소프트웨어 개발 단계를 자동화하는 기법이라고 한다.

과정은 아래와 같다.

  • 소스코드의 변경을 감지
  • CI/CD 시스템에서 빌드
  • 자동 테스트
  • CI/CD 시스템이 배포

Jenkins

널리 알려진 CI/CD 프레임워크 중 하나로, 오픈소스 소프트웨어이므로 쉽게 접할 수 있었다. Github Webhook 통합과 Web GUI 제공 및 다양한 서드파티 플러그인 지원으로 많은 사람들이 쓰고 있을 소프트웨어라고 생각한다.

Node 스크립트를 동작시키는 플러그인을 가졌다고 하여 이를 사용하려고 한다.

진행

진행 과정은 아래와 같다.

  • Docker 설치
  • Jenkins 컨테이너 생성
  • Nginx로 Reverse-Proxy
  • Jenkins 기본 설정

환경

  • Ubuntu 22.04.3 LTS in Oracle Cloud (OCI)

Docker 설치

Docker란 간단히 이야기하자면 가상 머신은 아니지만 가상적인 리눅스 샌드박스인 '컨테이너'를 제공함으로써 환경 분리를 성사시켜주는 소프트웨어다. 이미 만들어진 환경인 '이미지'를 다운로드 받아서 컨테이너를 생성하고 사용할 수 있다.

Jenkins가 설치된 이미지로 컨테이너를 생성하려고 한다. 일단 Docker를 설치해야 한다. 현재 우분투를 사용하고 있으므로 이 문서를 보고 root 권한으로 아래 명령들을 실행하면 만사 OK다.

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

단순히 Docker의 GPG 키를 설치하고 APT Repository를 추가하는 과정이다. 굳이 위를 창작하며 쓸 이유는 없으므로 복사 붙여넣기했다.

이제 운영체제에 Docker가 설치되었다.

Jenkins Container 생성

docker run -d --name jenkins --restart=on-failure \
-p 8080:8080 \
-v /var/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-e TZ=Asia/Seoul \
-u root \
jenkins/jenkins

이 블로그를 참조하였다.

  • -d는 detached의 의미로 백그라운드에서 컨테이너가 돌아가게 한다.
  • --restart=on-failure : 컨테이너 실패 시 재시작한다.
  • -p 8080:8080 : 컨테이너가 8080포트를 사용할 것임을 의미한다.
  • -v : volume이라는 뜻이다. A:B 라고 하면, A는 local, B는 container 내부의 경로를 의미하여 A를 B에 마운트시킨다.
    • 로컬 경로인 /var/jenkins_home과 컨테이너 내부 경로인 /var/jenkins_home을 링크했다. 즉, 컨테이너에서 해당 폴더가 수정될 경우 도커 밖의 폴더도 업데이트된다.
    • /var/run/docker.sock을 링크했다. 이것은 컨테이너 내부에서도 docker 명령을 사용할 수 있도록 한다. docker out of docker라고 한다.
  • -e: environment. 즉 컨테이너 내부 환경 변수를 설정할 수 있다. Timezone을 설정해줬다.
  • -u root : user root. 컨테이너가 root 권한을 사용하도록 했다.
  • jenkins/jenkins: 사용할 docker 이미지 이름이다.

위 명령을 실행시키면, 병렬적으로 이미지를 다운로드(pulling)하는 것을 볼 수 있다. 그리고 빠르게 컨테이너가 생성되고 실행되며, 생성된 컨테이너의 UID가 출력된다.

Nginx로 Reverse-Proxy

기본적으로 Jenkins는 HTTP 웹 서비스이다. 따라서 HTTP를 싫어하는 본인과 같은 경우라면 이 글을 참조하고, 그냥 HTTP를 통해 서비스를 이용하고 싶다면 이 단계를 건너뛰어도 상관 없다.

나는 현재 호스트 자체에 Nginx가 설치되어 있는 경우이므로, Docker에 Nginx를 깔고 두 개의 컨테이너에 대해 compose하는 경우를 생각하지 않을 것이다. 많은 사람들이 이 경우에 대해서 글을 작성해놨으므로, 혹여나 Nginx가 설치되어 있지 않은데 Docker에 모든 것을 때려박고 싶은 사람이라면 그러한 글들을 찾는 것이 좋다.

Jenkins는 8080포트를 사용한다. 이를 Reverse-Proxy 해줄 생각이다.

Jenkins는 웹소켓과 같은 기술들도 사용하므로, 적당히 proxy_pass만을 써서는 안된다. 이 문서를 참조하여 아래와 같은 가상 호스트 설정을 작성해보았다.

server{
    listen 80;
    listen [::]:80;

    server_name leroy.jenkins.ppp;
    location / {
        return 301 https://$host$request_uri;
    }
}

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}


server{
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name leroy.jenkins.ppp;

    ssl_certificate /etc/letsencrypt/live/leroy.jenkins.ppp/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/leroy.jenkins.ppp/privkey.pem;

    access_log /var/log/nginx/jenkins.access.log;
    error_log /var/log/nginx/jenkins.error.log;

    ignore_invalid_headers off;



    location / {
        proxy_pass http://localhost:8080;
        proxy_redirect default;
        proxy_http_version 1.1;

              # Required for Jenkins websocket agents
        proxy_set_header   Connection        $connection_upgrade;
        proxy_set_header   Upgrade           $http_upgrade;
        proxy_set_header   Host              $http_host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_max_temp_file_size 0;

      #this is the maximum upload size
        client_max_body_size       10m;
        client_body_buffer_size    128k;

        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;
        proxy_request_buffering    off; # Required for HTTP CLI commands
        proxy_set_header Connection ""; # Clear for keepalive
    }
}

이제 leroy.jenkins.ppp으로 접속하면 나의 Jenkins를 확인할 수 있을 것이다. 물론 저 사이트는 없다.

Jenkins가 설치되었다.

기본 설정

접속을 하면 처음 바로 비밀번호를 작성하라는 페이지가 출현할 것이다. (사진이 없다...)
/var/jenkins_home/secrets/initialAdminPassword
파일을 참조하면 쉽게 초기 비밀번호를 획득할 수 있다.

이제 설치 창이 뜰 것인데, 가볍게 왼쪽 기본 설치 옵션을 이용하여 Jenkins 설치를 마무리하자.


설치가 완료되었다면, 처음 Admin 계정을 생성하는 페이지가 뜰 것이다. 적당히 생성해주고 Save 버튼을 눌러 진행하자. 이제 Jenkins를 사용할 준비가 되었다.

오른쪽 위에 매우 거슬리는 알림이 우리를 반겨준다. 이는 보안 관련 권장 사항을 알려주는 것이므로, 할 수 있는 사람은 하자.
내용은 다음과 같다.
젠킨스 컨트롤러를 호스팅하는 머신에서 빌드 스크립트를 실행하게 하는 것은 보안상 바람직하지 않은 정책이므로 빌드 작업을 수행하는 Agent 또는 Cloud Service를 지정하라는 것이다. 그러한 서비스가 나에겐 없으므로 일단 Dismiss하기로 했다.

왼쪽 메뉴에서 Jenkins 관리에 들어가면 Jenkins를 마음껏 사용자 설정할 수 있다. 이는 나중에 다뤄보도록 하겠다.

~完~

profile
THXX FOR EVERYTHING

0개의 댓글

Powered by GraphCDN, the GraphQL CDN