Deploy Minecraft by Docker

시작

언젠가 현실 친구 채팅방에서 ‘우리 다같이 한 것이 뭐가 있었냐?’ 하면서 이야기가 있었는데, 갑자기 마인크래프트 이야기가 나오게 되어 구축하게 되었다.

…는 마인크래프트 서버 구축이 처음은 아니었는데, 지금으로부터 10개월 전에 EC2라는 모드를 넣고 구축한 적이 있었다. 다만, 오래 못 갈 뿐이었다.

하지만, 이번에는 바닐라 기반으로 하자는 이야기가 나왔고, 약 6일 정도 운영하게 되었다.

6일 정도 운영하다보니 나름대로 문제와 이를 해결하기 위한 여러 방안을 구축해서 사용했고, 그 결과 현재는 다음과 같은 구조를 가지게 되었다.

Nodap-MC 서버 구성도

먼저, 마인크래프트 서버라고 해서 단순히 마인크래프트만 돌린다는 것은 전혀 아니다. 그럴 수도 있지만, 가령 아래와 같은 문제가 발생하게 된다.

  • 서버 관리자가 바빠서, 문제가 생겼을 때 복구할 수 없음
  • 오랜 시간 키고 있으면 반응이 느려지는 일이 있고, 서버 컨테이너를 재시작할 필요가 있음

따라서, minecraft 컨테이너 외에 여러 컨테이너들을 동시에 운영하게 되었고, 각각의 역할은 다음과 같다.

  • minecraft: 마인크래프트 서버. 좀 더 나은 성능을 위해 PaperMC 1.15.2 와 adoptOpenJdk11 버전을 사용.
  • rcon: minecraft 서버의 콘솔 접근에 사용되는데, 이는 op 권한을 아무도 갖고 있지 않기 때문이다.
  • Caddy: 외부에서 80, 443 으로 들어온 접근에 대해 각 컨테이너로 연결시킨다.
    • Nginx를 사용할 수도 있었지만, 이번에는 좀 더 간단하다는 Caddy를 사용했다. 제일 마음에 드는 점은, 각 연결 통로마다 tls [email protected] 라고 적어두면 Let’s Encrypt로 통해 인증서를 받아와서 Signing한다는 것이다.
  • Portainer: 웹 UI로 컨테이너나 이미지들에 대해 관리할 수 있고, 로그를 볼 수 있게 하는 도구이다. 서버 관리자(= 필자 본인)이 바쁘기 때문에, 문제가 생겼을 때 누군가가 빠르게 서버를 재부팅해서 사용할 수 있도록 구축했다.
  • Grafana, Prometheus, cAdvisor: cAdvisor는 각 컨테이너에 대한 metrics를 제공하고, Prometheus는 cAdvisor가 수집한 metrics를 저장하는 역할을 맡고, Grafana는 이를 그래프로 수치화해서 보여주는 역할이다. 여기서, Grafana Alerts를 이용하여 메모리 사용량이 일정량 이상일 때 텔레그램으로 경고 메세지를 보낸다.

구축 정리

구축에 사용된 서버는 Vultr 4vCPU 8GB 사양이다.

기본 과정

Ubuntu 기준이며, https://docs.docker.com/install/linux/docker-ce/ubuntu/ 를 참고한다.

sudo apt update
sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL <a href="https://download.docker.com/linux/ubuntu/gpg">https://download.docker.com/linux/ubuntu/gpg</a> | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository "deb [arch=amd64] <a href="https://download.docker.com/linux/ubuntu">https://download.docker.com/linux/ubuntu</a> bionic stable"
sudo apt update
sudo apt install docker-ce docker-ce-cli <a href="http://containerd.io">containerd.io</a>
sudo curl -L "<a href="https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$">https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$</a>(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

여기까지 9개의 Command를 실행하여 Docker-CE 버전과 docker-compose를 설치할 수 있다.

마인크래프트 서버 (itzg/minecraft-server)

version: '2'

services:
  minecraft:
    image: itzg/minecraft-server:adopt11
    container_name: "minecraft"
    ports:
      - ...
    environment:
      - EULA=TRUE
      - ENABLE_RCON=TRUE
      - RCON_PASSWORD=...
      - MEMORY=7G
      - TYPE=PAPER
      - VERSION=1.15.2
      - SERVER_PORT=...
    restart: always
    
  rcon:
    image: itzg/rcon
    container_name: "rcon"
    links:
      - minecraft
    networks:
      - nodap-mc-network

networks:
  nodap-mc-network:
    external: true

만약 Forge 기반의 모드를 사용하고자 하면 TYPE=FORGE로 통해 Forge 기반 서버로 사용할 필요가 있다. 처음에 Forge 기반으로 사용했었으나 메모리 사용량이나 서버가 급격하게 무거워지는 문제가 있었기에, PaperMC 를 사용하게 되었다.

rcon 에 연결된 networks인 nodap-mc-network 는 후술할 예정이지만 Caddy가 각 컨테이너로 연결할 수 있게 묶어주는 역할을 한다. TCP로 연결되어 따로 네트워크를 묶을 필요가 없는 minecraft는 기재하지 않았다.

Portainer 서버 (portainer/portainer)

Portainer 서버는 상기하였듯이 컨테이너의 관리를 웹 UI로 할 수 있다.

version: ‘2’

services:
  portainer:
    image: portainer/portainer
    restart: always
    container_name: "portainer-app"
    command: -H unix:///var/run/docker.sock
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - nodap-mc-network

networks:
  nodap-mc-network:
    external: true

여기에서도 nodap-mc-network로 묶어주었다.

모니터링 Stack

모니터링 스택은 상기하였듯이 컨테이너의 CPU/메모리/네트워크 사용량을 볼 수 있게 한다.

cAdvisor 서버 (google/cadvisor)

cadvisor: image: google/cadvisor:latest container_name: cadvisor volumes: – /:/rootfs:ro – /var/run:/var/run:ro – /sys:/sys:ro – /var/lib/docker/:/var/lib/docker:ro – /dev/disk/:/dev/disk:ro restart: always networks: – nodap-mc-network

cAdvisor 등이 외부에 노출될 필요는 없으나 필요할 경우, 8080:8080 포트를 추가하여 웹 UI를 볼 수 있다.

Prometheus 서버 (prom/prometheus)

prometheus:
    image: prom/prometheus
    container_name: prometheus
    restart: always
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
    networks:
      - nodap-mc-network

설정에 필요한 prometheus.yml는 다음과 같다.

global:
  scrape_interval: 15s 

  external_labels:
    monitor: 'nodap-mc-monitor'

scrape_configs:
  - job_name: 'cAdvisor'
    scrape_interval: 5s
    static_configs:
    - targets: ['cadvisor:8080']

Grafana 서버 (grafana/grafana)

grafana: image: grafana/grafana container_name: grafana environment: – GF_SECURITY_ADMIN_PASSWORD= volumes: – grafana-storage:/var/lib/grafana depends_on: – prometheus networks: – nodap-mc-network

그리고, Grafana Alerts를 이용하여 알림 기능을 구현하였는데, 위 Memory Usage 의 빨간색 부분이 기준치이다.

알림 룰은 간단하게 진행하였는데, 매 20분마다 5분간의 평균 메모리 사용량이 7301444403 Bytes (= 6.8GiB) 를 넘으면 Notification을 보내주는 규칙이다.

이 세 서버를 모두 정의하면 다음과 같다.

version: ‘2’

services:
  cadvisor:
    image: google/cadvisor:latest
    container_name: cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
      - /dev/disk/:/dev/disk:ro
    restart: always
    networks:
      - nodap-mc-network

  prometheus:
    image: prom/prometheus
    container_name: prometheus
    restart: always
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
    networks:
      - nodap-mc-network

  grafana:
    image: grafana/grafana
    container_name: grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=
    volumes:
      - grafana-storage:/var/lib/grafana
    depends_on:
      - prometheus
    networks:
      - nodap-mc-network

volumes:
  grafana-storage:

networks:
  nodap-mc-network:
    external: true

Caddy 서버 (abiosoft/caddy)

Caddy는 Go로 작성된 웹 서버로 간단한 사용법으로 TLS certificate 관리, 리버스 프록시, 정적 파일 호스팅 등의 많은 기능을 제공한다.

version: ‘2’

services:
  caddy:
    image: abiosoft/caddy
    container_name: caddy
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - .Caddyfile:/etc/Caddyfile
      - .caddy:/root/.caddy
    restart: always
    networks:
      - nodap-mc-network

networks:
  nodap-mc-network:
    external: true

그리고, 설정 파일이기도 한 Caddyfile는 다음과 같다.

***1.uzuki.live {
    proxy / portainer:9000
    tls [email protected]
}

***2.uzuki.live {
    proxy / grafana:3000
    tls [email protected]
}

***3.uzuki.live {
    proxy / rcon:4326
    tls [email protected]
}

***[1~3].uzuki.live 가 하나의 사이트로 인식하게 되며, 각 사이트는 컨테이너:포트 로의 proxy 기능과 tls [email protected] 를 가지게 된다.