ghost를 컨테이너에 설치하는 방법

ghost를 컨테이너에 설치하는 방법

Google Compute Engine (GCE)에서 fly.io로 이사를 갔지만, fly.io에서 무료로 제공하는 메모리 용량이 256mb 밖에 되지 않아 자주 다운 되는 일이 발생하였다. 그래서 다시 GCE의 무료 인스턴스로 돌아가는 김에, 서버 자체에 설치하지 않고 Docker 컨테이너를 이용해서 설치하게 되었다.

지금 GCE의 무료 인스턴스는 E2-micro, 1GB Ram, 30GB 표준 SSD가 제공되고 있다. 리전을 미국 밖에 선택할 수 없고 미국 외로 나가는 egress가 1GB 밖에 지원이 안되기 때문에 매달 아주 소액의 비용이 발생할 것 같기는 하지만 좀 더 안정적이고 스트레스 없이 이용하는 비용이라 생각하기로 했다.

CDN을 앞단에 설치하면 egress 비용도 최소화 할 수 있을 거 같으니 그건 추후 다른 포스팅에서 알아보도록 하고 이번 포스팅에서는 ghost를 docker로 운영하는 법에 대해 알아본다.

OS는 Ubuntu 22.04 LTS를 사용하였다.


# Swap Memory

ghost에서 권장하는 사양은 최소 1GB Ram이다. GCE의 무료 tier는 1GB Ram으로 최소 사양을 충족하는 것 같지만, 이번엔 docker도 사용하고 db는 sqlite가 아닌 mysql을 사용할 거라 메모리가 부족 할 수 있다.

다행히도 SSD 메모리는 30GB로 넉넉하기 때문에 이 중에 일부분을 swap memory로 할당해서 모자랄 수 있는 Ram을 아쉬운대로 추가로 만들어 준다.

우선 현재 메모리 사용량을 확인하기 위해선 free -h 커맨드를 사용한다. Swap이라는 열에 아무것도 할당이 안되어 있는 것을 확인할 수 있다.

Swap 메모리를 만들기 위해서는 다음 커맨드를 실행한다.

sudo fallocate -l 1G /swapfile

1G 정도만 추가해주면 넉넉할 거라 생각되지만 사용환경에 따라 늘이거나 줄이면 된다.

다음으로 root 유저만이 액세스 할 수 있게 권한을 바꿔준다.

sudo chmod 600 /swapfile

ls -lh /swapfile 커맨드를 실행해서 다음과 같이 나오면 제대로 반영된 것이다.

-rw------- 1 root root 1.0G Jun 18 11:14 /swapfile

권한을 설정했으면 이제 할당한 파일을 실제로 Swap으로 적용할 차례.

sudo mkswap /swapfile

시스템이 swap 메모리를 사용하도록 swap on.

sudo swapon /swapfile

어떤 파일이 현재 swap 메모리로 사용되도록 설정되었는지는 sudo swapon --show로 확인 할 수 있다.

시스템이 재부팅 됐을 때도 자동으로 swap이 실행되도록 설정파일을 수정.

sudo nano /etc/fstab

마지막 줄에 다음 내용을 추가해주고 저장.

/swapfile none swap sw 0 0

이상으로 swap 메모리 설정이 끝났다. 다음은 swap 메모리를 어떤 식으로 사용할 건지에 대한 설정을 해준다.

너무 자주 swap 메모리를 사용하는 것도 퍼포먼스에 영향을 줄 수 있으니 되도록이면 Ram을 우선적으로 사용하도록 swapiness를 낮춰준다. 현재 설정되어있는 swapiness는 cat /proc/sys/vm/swappiness로 확인 할 수 있는데 기본값은 60으로 설정되어있다. 이 수치가 높을수록 swap 메모리를 더 적극적으로 사용하게 된다. 수치는 0~100 사이로 설정. 여기선 이 수치를 10으로 설정하도록 한다.

sudo sysctl vm.swappiness=10

다음으로는 캐시 데이터를 어느정도의 빈도로 clear 할건지에 대한 설정. cat /proc/sys/vm/vfs_cache_pressure로 현재 값을 볼 수 있다. 기본값은 100으로 설정되어있는데 이 값을 50으로 조정해준다. 수치는 0~100 사이로 설정 할 수 있는데 높을 수록 캐시를 빨리 삭제하게 된다.

sudo sysctl vm.vfs_cache_pressure=50

마지막으로 재부팅 했을 때 설정한 값들이 기본적으로 적용되도록 설정 파일도 수정.

sudo nano /etc/sysctl.conf

다음 2줄을 추가해주고 저장.

vm.swappiness=10
vm.vfs_cache_pressure=50

이걸로 swap 메모리에 대한 설정은 끝.


# Docker 설치

다음은 시스템에 docker를 설치해야한다.

sudo apt-get update

# Dependency 설치
sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release

# Docker 공식 GPG key 추가
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# Docker 리포지토리 설정
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  
# 리포지토리 업데이트
sudo apt-get update

# Docker 설치
sudo apt-get install docker-ce docker-ce-cli containerd.io

# Docker-compose 설치
sudo apt-get install docker-compose

# Docker가 설치됐나 확인
docker --version

# Docker-compose가 설치됐나 확인
docker-compose --version

다 설치했으면 현재 사용자를 docker 그룹에 추가해주자.

sudo usermod -aG docker ${USER}

# nginx 설치

nginx 설치는 간단하다.

# nginx 설치
sudo apt-get install nginx

# 80번과 443번 포트 허용
sudo ufw allow 'Nginx Full'

# docker-compose.yml

컨테이너 설정 파일을 만들어준다. 아무곳에나 만들어도 되지만 관리하기 쉽게 /docker/<도메인명>경로에 만드는 것을 추천. 예제는 도메인명이 example.com이라고 가정한다. 자신의 도메인으로 변경해서 사용하자.

# 폴더 만들기
sudo mkdir -p docker/example.com

# 폴더로 이동
cd docker/example.com

# docker-compose.yml 파일 생성
sudo nano docker-compose.yml

다음과 같이 적는다. 메일 서비스 관련 변수들은 없어도 ghost를 사용하는데 지장은 없지만 사용하고 싶다면 지메일을 활용하는 방법에 대해서 알아본 이전에 작성한 포스팅을 참고.

version: "3.3"

services:
  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 8080:2368
    volumes:
      - ~/data/content:/var/lib/ghost/content
    environment:
      # db관련 설정
      database__client: mysql
      database__connection__host: db
      database__connection__user: ghost
      database__connection__password: <mysql ghost 유저의 비밀번호>
      database__connection__database: ghost
      
      # 메일 서비스 관련 설정
      mail__from: <보내는 사람 이메일 주소>
      mail__options__auth__pass: <메일 서비스 비밀번호>
      mail__options__auth__user: <메일 서비스 이메일 주소>
      mail__options__service: gmail
      mail__transport: SMTP
      
      url: <자신의 도메인명>
  db:
    image: mysql:8.0
    restart: always
    volumes:
      - ~/data/db:/var/lib/mysql
    ports:
      - 13928:3306
    environment:
      MYSQL_ROOT_PASSWORD: <mysql root 비밀번호>
      MYSQL_DATABASE: ghost
      MYSQL_USER: ghost
      MYSQL_PASSWORD: <mysql ghost 유저의 비밀번호>

MYSQL_ROOT_PASSWORD의 경우 컨테이너가 처음 실행될 때 설정되는 root 유저에 대한 비밀번호이다. 추후에 바꾸고 싶다면 컨테이너 안에 들어가서 바꿔야한다.

사용하는 이미지 파일은 항상 최신 파일을 사용하도록 ghost:latest를 이용하였다.
자신의 환경에 맞게 필요한 부분을 바꿔주고 sudo docker-compose up -d로 컨테이너 활성화.

docker ps 커멘드로 컨테이너가 제대로 작동하고 있는지 확인까지 해주면 끝.


# nginx 설정

컨테이너에 ghost 서비스를 8080에 지정해두었기 때문에 서버로 들어오는 리퀘스트를 8080에서 돌아가고 있는 ghost로 보내주는 설정을 해주자.

우선 sites-available에 설정 블록 관련 파일을 작성.

sudo nano /etc/nginx/sites-available/<도메인명>

다음과 같이 리버시 프록시를 설정해준다.

server {
    server_name  <도메인명>;
    index index.html index.htm;
    access_log /var/log/nginx/ghost.log;
    error_log  /var/log/nginx/ghost-error.log error;
    
    # 업로드 파일 크기 제한. 100메가 정도면 충분하지만 기존의 글들을 import 할 때 json 파일 크기가 크다면 그 파일 사이즈보다 크게 설정해야 import를 할 수 있다.
    client_max_body_size 100M;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:8080;
        proxy_redirect off;
    }
}

site-enabled에 링크해주면서 설정을 활성화.

sudo ln -s /etc/nginx/sites-available/<도메인명> /etc/nginx/sites-enabled/<도메인명>

설정 파일에 문제가 없는지 확인하고 nginx 재시작.

sudo nginx -t
sudo nginx -s reload

여기까지 설정했으면 http://<도메인명> 으로 ghost에 접속 할 수 있을 것이다. 물론 도메인 레지스트리에 A레코드를 서버의 아이피 주소로 먼저 설정해둬야만 가능하다. 그 부분은 이번 포스팅과 관련이 없기 때문에 생략한다.


# certbot

마지막으로 SSL 통신을 가능하게 하기 위해 certbot를 설치한다.

sudo apt install snapd
sudo snap install --classic certbot

certbot을 실행하여 SSL 인증서를 발급 받는다.

sudo certbot --nginx -d <도메인명>

인증서는 90일 동안 유효하다. 예전에는 주기적으로 자동으로 인증서를 갱신해주는 cron job을 따로 설정해줘야 했는데 요즘엔 certbot으로 인증서를 설치하면 알아서 자동 갱신되도록 설정해주니 매우 편하다. nginx 설정도 알아서 https로 강제 라우팅 되도록 설정해주기 때문에 따로 nginx의 서버 블록을 설정하지 않아도 된다. 위 커맨드 하나로 다 해결.


이상으로 ghost와 mysql을 docker 컨테이너 안에서 실행하는 방법에 대해 알아보았다. mysql까지 필요한가 싶어서 그냥 지금까지 계속 sqlite를 사용해왔지만 ghost v5 부터는 sqlite는 프로덕션 버전에서는 공식적으로는 지원하지 않기도 하고, 버전을 업데이트 할 때 마다 문제가 생길 가능성도 있어서 이번 기회에 그냥 mysql로 전환하였다.

모르는 사이에 회원 관리창의 번역 기능도 탑재되어 있기도 해서 점점 영어권 이외의 언어에서도 사용하기 편리하도록 바뀌고 있으니 앞으로 꾸준히 버전을 업데이트 해 볼 예정이다.