도커

[DOCKER] 주피터 노트북 HTTPS 적용

우쿠_ 2023. 10. 30. 16:07

0. 들어가기 앞서

이전 포스팅인 [CertBot] SSL 와일드카드 인증서 받기 [Docker] 주피터 노트북 생성 를 보고 오면 도움이 된다.

내 부끄러운 코드를 실행하는 주피터 노트북은 기본적으로 HTTP로 작동되는 상태다. 이말은 즉 내 주피터 노트북 서버 까지 가는 네트워크 장비 중 한개라도 보안 사고가 발생하면 부끄러운 내 코드가 만 천하에 공개될수 있다. 그렇기 때문에 HTTPS 를 적용할 예정이다.

HTTPS 는 nginx 와 apache 웹 서버와 같은 웹 엔진으로 리버스 프록시를 사용하여 적용한다.

 

1. 공식문서

이번 포스팅은 도커의 엔진엑스 이미지를 가지고 리버스 프록시를 설정 할 예정이다.

블로그를 따라하는것도 좋지만 공식문서를 보자.

눈물을 머금고 60개월 풀할부로 산 K8 의 메모리시트 사용법은 옆집 준식이보다 기아 메뉴얼이 더 잘 알려주기 때문이다.

하지만 공식 문서의 알짜배기만 필요한 사람들을 위해 공식문서를 보며 소개하겠다.

 

2. 준비물

준비물은 SSL 인증서가 필요하다. SSL 인증서가 없는 경우[CertBot] SSL 와일드카드 인증서 받기 로 SSL 인증서를 받아오자.

또한 주피터 노트북의 컨테이너 혹은 주피터 노트북도 실행중인 상태여야 한다. 여기서는 3333 번 포트로 주피터 노트북이 실행중임을 가정한다.

 

3. 설정 확인

먼저 주피터 노트북의 실행 포트를 봐야한다. 블로그 주인장은 도커로 주피터 노트북을 실행중이다.

docker ps -a

 

이렇게 됬다면 nginx 를 설정해야 한다. 기본적으로 http 로 들어오는건 https 로 바꿔주고, https 로 들어온 패킷은 주피터 노트북으로 바인딩 시켜줘야 한다. 그 역할을 리버스 프록시 설정으로 해주는 것이다.

공식문서를 보면 클라이언트는 NGINX 에 요청하면 클라이언트가 바로 프록시 서버에 가는게 아닌 NGINX 가 프록시 서버에 접속 한후 그 응답을 클라이언트에 전달해주는 역할을 한다고 한다. 지원하는 프로토콜은 FastCGI, uwsgi, memcached 가 있다고 한다. 

또한 http 프록시 서버에 요청을 전달하려면 proxy_pass 를 지정해주면 된다고 한다.

 

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

이렇게 말이다. 

 

하지만 이렇게 하면 문제가 있다. nginx 가 프록시 서버에 접속하는꼴이 되므로 실제로 누가 요청했는지 헤더값을 설정 해 줘야 한다.

 

엔진엑스 공식 문서에서도 Request 헤더를 추가 해줘야 한다고 한다.

location /some/path/ {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://localhost:8000;
}

이런식으로 말이다.

하지만 주피터 노트북은 websocket 도 사용한다. 그렇기 때문에 웹소켓도 설정 해야한다.

공식문서에 매우 친절히 나와있다.

세가지 헤더만 추가 하면 된다고 한다.

proxy_http_version     1.1;
proxy_set_header      Upgrade "websocket";
proxy_set_header      Connection "Upgrade";
proxy_read_timeout    86400;

 

4. 설정 적용

위의 3장의 설정을 잘 보면 https 로 들어오는걸 주피터 노트북에 연결만 해주면 끝이다. nginx 가 http 로 주피터 노트북에 접속해야 함으로 proxy_pass 를 사용 해야 하며, 헤더값을 지정하여 주피터 노트북이 엔진엑스가 아닌 클라이언트의 실제 호스트와 실제 ip의 값을 지정해줘야 한다.

이렇게 말이다

vim /etc/nginx/conf.d/default.conf

 

server {
    listen 443 ssl;
    server_name localhost;

    ssl_certificate /etc/letsencrypt/live/[mydomain.com]/fullchain.pem;  # SSL 인증서 파일
    ssl_certificate_key /etc/letsencrypt/live/[mydomain.com]/privkey.pem;  # SSL 키 파일

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://[주피터노트북IP]:[주피터노트북포트];
        proxy_http_version     1.1;
        proxy_set_header      Upgrade "websocket";
        proxy_set_header      Connection "Upgrade";
        proxy_read_timeout    86400;
    }

}

server {
    listen 80;
    server_name localhost;
    return 301 https://$host$request_uri;
}

이렇게 말이다.

 

주피터노트북IP와 포트, mydomain환경에 맞게 바꿔줘야 한다. 아래는 블로그 주인장의 conf다.

블로그 주인장은 3333포트를 사용중이기 때문에 저렇게 설정해줬다.

5. 확인해보기

이제 다 되었다면 도커로 nginx 를 실행해보면 끝이다.

아래 명령어를 실행해서 한번 확인해보자.

docker run  --name nginx -p 80:80 -p 443:443 -d -v /etc/nginx/conf.d:/etc/nginx/conf.d -v /etc/letsencrypt:/etc/encrypt nginx

 

HTTPS 가 야무지게 적용된다.

 

6. Docker-Compose 설정

지금 3333번 포트는 외부에 열려있다. 직접 WAS(주피터 노트북)을 외부에 노출하는것은 별로 좋지 않은 행위다. 그래서 실제 배포 할때는 nginx 만 외부에 열고 나머지는 다 차단한다.

또한 주피터 노트북이 실행이 안된 상태에서 nginx 를 켜봤자 말짱 도로묵이기 때문이다.

그러면 어떻게 하면 WAS 를 외부에 노출하지 않으면서 주피터 노트북이 실행 되야만 nginx 를 실행시킬수 있을까?

우리는 도커를 사용중이다. 도커는 해당 솔루션을 docker-compose 를 통해 제공한다.

먼저 아무데나 Docker-compose.yml 파일을 아래와 같이 만들자.

jupyter-3.9 의 3333:8888 을 없애고 컨테이너를 jupyter-network 라는 어댑터로 묶었다. 이렇게 하면 컨테이너명이 아이피가 된다.

cd
vim docker-compose.yml

 

version: '3'
services:
  nginx:
    image: nginx
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /etc/nginx/conf.d:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt
    restart: always
    depends_on:
      - jupyter-3.9
    networks:
      - jupyter-network

  jupyter-3.9:
    image: jupyter/minimal-notebook:python-3.9.7
    container_name: jupyter-3.9
    environment:
      - DOCKER_STACKS_JUPYTER_CMD=notebook
    volumes:
      - /home/ubuntu/jupyter:/home/jovyan
    restart: always
    networks:
      - jupyter-network

networks:
  jupyter-network:

이렇게 만들었으면 모든 컨테이너를 종료 후 삭제시킨다.

docker stop nginx
docker stop jupyter-3.9
docker rm nginx
docker rm jupyter-3.9
docker ps -a

 

또한 nginx.conf도 아래와 같이 수정해줘야 한다.

vim /etc/nginx/conf.d/default.conf
server {
    listen 443 ssl;
    server_name localhost;

    ssl_certificate /etc/letsencrypt/live/[mydomain.com]/fullchain.pem;  # SSL 인증서 파일
    ssl_certificate_key /etc/letsencrypt/live/[mydomain.com]/privkey.pem;  # SSL 키 파일

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://jupyter-3.9:8888;
        proxy_http_version     1.1;
        proxy_set_header      Upgrade "websocket";
        proxy_set_header      Connection "Upgrade";
        proxy_read_timeout    86400;
    }

}

server {
    listen 80;
    server_name localhost;
    return 301 https://$host$request_uri;
}

꼭 proxy_pass http://jupyter-3.9:8888 은 바꾸면 안된다!

그 후 docker-compose.yml 파일이 있는곳에 가서 실행하면 된다.

docker-compose up

 

 

접속 확인을 해보자.

 

또 이제 8888 로 들어가면 접속이 안됨을 볼 수 있다.

 

'도커' 카테고리의 다른 글

[DOCKER] 도커로 Django 배포하기  (0) 2023.11.07
[Docker] 주피터 노트북 생성  (1) 2023.10.20
도커설치 - 우분투  (0) 2023.10.20