Docker Jenkins 설치 및 nginx https 적용 방법

먼저 Jenkins Docker 설치 방법을 살펴보겠습니다. 그리고 해당 Jenkins는 경우에 따라 외부 네트워크에서도 접근해야 할 필요성이 생깁니다. 이를 위해서 Jenkins 컨테이너에 대한 nginx https 적용 방법까지 알아보도록 하겠습니다.

Docker Jenkins 설치 개요

우선 Docker Compose를 이용해서 Jenkins를 설치할 것입니다. 그리고 Nginx에서 HTTPS 설정을 해 줄 것입니다.

Jenkins 컨테이너 설정

Jenkins 컨테이너 이름, 이미지, 재시작, 포트 설정

compose.yaml에 아래와 같이 추가해 줍니다.

services:
  jenkins:
    container_name: jenkins
    image: jenkins/jenkins:lts-jdk11
    restart: always
    ports:
      - 38080:8080
YAML

저는 컨테이너의 이름을 jenkins로 설정했습니다. 사용하고 싶은 컨테이너 이름을 사용하면 됩니다.

Docker Jenkins 설치 Image는 jenkins/jenkins:lts-jdk11를 사용할 것입니다. Deprecated jenkins 도커 이미지가 dockerhub에 있으므로 주의하시기 바랍니다.

그리고 서버가 죽으면 무조건 재시작하게 하기 위해서 restart 값을 always로 준비해 줍니다.

https를 사용하지 않은 로컬에서도 접속할 수 있도록 포트를 설정해 줍니다. 위와 같이 하면 http://localhost:38080 으로 jenkins 컨테이너의 8080포트로의 접속이 가능합니다.

젠킨스 홈 디렉토리 설정

이제 jenkins_home 디렉토리를 설정하겠습니다. home 디렉토리를 volumes으로 잡아두지 않으면, 젠킨스 컨테이너를 시작했을 때 jenkins_home은 다시 리셋됩니다. 그러므로 꼭 volumes에 Jenkins 홈 디렉토리를 설정해 주시기 바랍니다. 저는 jenkins_home 디렉토리는 호스트 머신의 /home/vm1/volumes/jenkins로 설정하겠습니다.

services:
  jenkins:
    container_name: jenkins
    image: jenkins/jenkins:lts-jdk11
    restart: always
    ports:
      - 38080:8080
    volumes:
      - /home/vm1/jenkins:/var/jenkins_home
YAML

여기까지 docker jenkins 설치를 위해 필요한 기본적인 작업을 compose.yaml에 했습니다. 이제 https로 접속을 하게 하려면 nginx 컨테이너를 설정해 주어야 합니다.

nginx 컨테이너 설정

저는 컨테이너 이름을 nginx로 설정하겠습니다. nginx 도커 이미지는 nginx:1.22.1를 사용하겠습니다. 마찬가지로 서버가 죽으면 무조건 재시작하게 합니다.

services:
  # ... jenkins 설정 여기에 있어요. nginx에 집중하시라고 생략했습니다.
  nginx:
    container_name: nginx
    image: nginx:1.22.1
    restart: always
YAML

80 포트로 외부 접속이 가능해야 하므로 80번 포트를 설정해 주고, https 설정을 위해 443번 포트도 설정해 줍니다.

services:
  # ... jenkins 설정 여기에 있어요. nginx에 집중하시라고 생략했습니다.
  nginx:
    container_name: nginx
    image: nginx:1.22.1
    restart: always
    ports:   # 포트 설정
      - 80:80
      - 443:443
YAML

사이트 설정을 nginx.conf에서 적용되게 하기 위해서 sites-enabled와 연결해 줍니다. 저는 로컬에 ~/docker-settings/nginx/sites-enabled 디렉토리와 연결해 주었습니다.

services:
  # ... jenkins 설정 여기에 있어요. nginx에 집중하시라고 생략했습니다.
  nginx:
    container_name: nginx
    image: nginx:1.22.1
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - /home/vm1/docker-settings/nginx/sites-enabled:/etc/nginx/sites-enabled
YAML

nginx에서 jenkins 컨테이너를 설정파일에 넣을 것이므로 depends_on 설정을 아래와 같이 해 줍니다. depends_on 설정을 해 주면, jenkins 컨테이너를 먼저 띄운 후에 nginx를 띄우게 됩니다. nginx 컨테이너가 먼저 뜨면서 jenkins를 찾지 못해서 생길 수 있는 문제가 사라집니다.

services:
  # ... jenkins 설정 여기에 있어요. nginx에 집중하시라고 생략했습니다.
  nginx:
    container_name: nginx
    image: nginx:1.22.1
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - /home/vm1/docker-settings/nginx/sites-enabled:/etc/nginx/sites-enabled
    depends_on:
      - jenkins
YAML

jenkins/nginx 컨테이너의 네트워크 설정

이제 네트워크를 설정할 차례입니다. 위에서 설정한 내용은 생략하고 네트워크 설정에 집중하기 위해서 네트워크 설정만 아래에 작성했습니다.

services:
  jenkins:
    # Jenkins 설정 생략
    networks:
      - my-network
  nginx:
    # nginx 설정 생략
    networks:
      - my-network

networks:
  my-network:
    name: my-network
YAML

포트는 호스트 주소로도 접속할 수 있게 포트를 8080으로 연결해 줍니다. 서버가 죽으면 항시 재시작하도록 restart 값은 always로 설정합니다.

Jenkins 컨테이너 네트워크 설정

네트워크를 my-network로 설정해서 이용합니다. nginx 설정에서 jenkins 컨테이너를 호스트로 이용할 것이기 때문에 네트워크 설정을 해줘야 합니다.

services:
  jenkins:
    # Jenkins 설정 생략
    networks:
      - my-network
  nginx:
    # nginx 설정 생략
    networks:
      - my-network

networks:
  my-network:
    name: my-network
YAML

완성된 compose.yml 파일은 다음과 같습니다.

services:
  jenkins:
    container_name: jenkins
    image: jenkins/jenkins:lts-jdk11
    restart: always
    ports:
      - 38080:8080
    volumes:
      - /home/vm1/jenkins:/var/jenkins_home
    networks:
      - my-network
  nginx:
    container_name: nginx
    image: nginx:1.22.1
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - /home/vm1/docker-settings/nginx/sites-enabled:/etc/nginx/sites-enabled
    depends_on:
      - jenkins
    networks:
      - my-network

networks:
  my-network:
    name: my-network
YAML

위의 compose.yml 파일 실행 전에 /home/vm1/jenkins 디렉토리와 /home/vm1/docker-settings/nginx/sites-enabled 디렉토리는 준비되어 있어야 합니다.

docker compose로 jenkins와 nginx 구동

docker compose up -d
ShellScript

이렇게 실행하면 아래와 같이 네트워크 my-network를 생성한 후, jenkins 컨테이너와 nginx 컨테이너를 차례로 구동합니다.

그림 1. docker compose로 jenkins와 nginx  구동
그림 1. docker compose로 jenkins와 nginx 구동

docker compose down 명령으로 jenkins와 nginx 구동 중지

참고로 구동 중인 모든 컨테이너를 중지 및 제거하고, compose.yaml에 설정된 네트워크를 제거해야 하는 상황에는 docker compose down 명령어를 사용해서 종료해 주면 됩니다.

그림 2. docker compose down 명령어로 구동중인 컨테이너 중지 및 제거
그림 2. docker compose down 명령어로 구동중인 컨테이너 중지 및 제거

jenkins와 nginx 컨테이너 구동 확인

그럼 jenkins와 nginx 컨테이너가 잘 떴는지 확인해 보겠습니다.

docker compose ps
ShellScript

Docker Jenkins 설치가 잘 되어서 아래와 같이 jenkins 도커 컨테이너가 잘 작동하고 있는 것을 확인할 수 있습니다. compose.yaml에서 설정한 대로 포트 설정도 모두 적용 됐습니다.

그림 2. docker 컨테이너 구동 상태 확인
그림 2. docker 컨테이너 구동 상태 확인

일단 기본적인 jenkins와 nginx 설정이 되었으니, 이제 https 설정을 하러 가겠습니다. 인증서는 발급 받아서 준비돼 있다고 가정하고, nginx에 설정해 보겠습니다.

Nginx SSL(https) 설정

~/docker-settings/nginx/sites-enabled/mydomain.conf를 편집해 줍니다. 인증서 설정과 관련해서 불필요한 설정은 모두 걷어냈습니다. mydomain.com과 같은 도메인 정보는 작업하는 도메인에 맞추어 조정하시기 바랍니다.

server {
    listen 80;
    server_name jenkins.mydomain.com;
    location / {
        rewrite ^ https://$server_name$request_uri? permanent;
    }
}

server {
    listen 443 ssl;
    server_name jenkins.mydomain.com;

    location / {
        proxy_pass http://jenkins:8080;
    }

    ssl_certificate /certs/jenkins_mydomain_fullchain.pem;
    ssl_certificate_key /certs/jenkins_mydomain_privkey.pem;
}
Nginx

SSL을 위한 설정을 위해서 우선 인증서가 필요합니다. Full Chain 파일과 Private Key 파일을 /home/vm1/certs 아래에 준비해 줍니다. 그리고 이에 맞추어서 compose.yaml 파일을 고쳐주어야 합니다. nginx의 volumes에 인증서 경로를 추가로 설정해 줍니다.

  nginx:
    # 위의 설정 생략
    volumes:
      - /home/vm1/docker-settings/nginx/sites-enabled:/etc/nginx/sites-enabled
      - /home/vm1/certs:/certs   # 여기 추가
    # 나머지 설정 생략
YAML

이제 준비가 되었습니다. 아래 명령으로 nginx 컨테이너를 재시작해서 추가된 mydomain.conf가 반영되게 해 줍니다.

docker restart nginx
ShellScript

이제 https://jenkins.mydomain.com으로 접속하면 SSL이 적용된 젠킨스 페이지를 확인할 수 있습니다. 아래 그림과 같이 자물쇠 표시가 제대로 나온다면 제대로 반영된 것입니다.

그림 3. Docker Jenkins 설치 후 SSL 인증서를 적용하여 https로 접속
그림 3. Docker Jenkins 설치 후 SSL 인증서를 적용하여 https로 접속

이제 https도 적용되었으니, 외부라면 https를 통해서 접근하면 되겠습니다. 내부 네트워크라면 굳이 https까지 이용하지 않아도 괜찮겠죠. 간단하게 localhost:38080 으로 접속해서 설치된 jenkins의 기본적인 설정을 하면 되겠습니다.

여기까지 Docker jenkins 설치와 nginx https 설정을 모두 마치겠습니다.

관련자료

Dockerhub의 jenkins/jenkins 페이지를 공유해 드리니 Docker Jenkins 설치를 위한 이미지는 여기에서 이용하기 바랍니다.

같이 읽으면 좋은 글

Nginx 로드 밸런싱 – https 서버 여러 대인 경우

처음엔 아래와 같은 방식으로 작성했는데, 이렇게 하는 경우 proxy_pass를 통해 https의 해당 도메인으로 정확히 연결되지 않는 현상을 발견하였다. 현재 사용할 서버는 PHP 아닌데, 왜 PHP가 뜨는 거지? 오잉? 싶었는데, 다른 서비스 용으로 PHP가 돌아가고 있었다. 즉, 엉뚱한 도메인으로 연결되고 응답으로 404 Not Found를 돌려받고 있었다. Oh my gosh! 왜 이런 현상이 생기는 것이지? 이건 분명 도메인으로 넘어가지 않고 IP로 넘어가서 발생한 현상일 듯한데 싶었다. 그렇다면 어떻게 이걸 명확하게 도메인으로 넘겨줄 수 있을지 고민이 되었다.

http {
  ...
  upstream servers {
    server first.myserver.com:443;
    server second.myserver.com:443;
  }

  server {
    listen 443 ssl;
    location / {
      proxy_pass https://servers;
    }
    ...
  }

}

그리고서 구글링을 하다가 힌트(https://stackoverflow.com/questions/29071168/nginx-upstream-with-http-https/65767299)를 발견한 후 아래와 같이 수정하였다.

http {
  ...
  upstream servers {
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
  }

  server {
    listen 443 ssl;
    location / {
      proxy_pass http://servers;
    }
    ...
  }

  server {
    listen 8081;
    location / {
      proxy_pass https://first.myserver.com;
    }
  }

  server {
    listen 8082;
    location / {
      proxy_pass https://second.myserver.com;
    }
  }

}

드디어 로드 밸런싱이 원하는대로 작동하기 시작했다.

정리해보면, nginx의 소스코드를 까보지 않아서 왜 이런 현상이 발생하는지는 정확히 모르겠지만, 추론컨대 전자의 경우 domain으로 작성하지만 IP와 포트로만 처리하는 것으로 보인다. 왜냐하면 동일 머신에 필자가 운용중인 다른 서비스로 접근하는 것을 확인했으니 말이다. 후자의 경우는 각각의 proxy 서버가 명확하게 목적지를 가리키고 있으므로 문제가 발생하지 않았던 것으로 보인다.

단일 서비스만 운용하는 경우에는 별 문제가 되지 않을 수 있겠지만, https로 이용하는 서비스가 여러 개 있다면 필자와 같이 문제가 발생할 수 있다.