2018 年 12 月から Heroku で動かしていたこの日記も Heroku の Free Dyno 廃止にともなって引っ越した。乞食運用を続けるとなると知ってる限りでは GCP (GCE) くらいしか選択肢が無いから移行先はすぐに決まった。PaaS から IaaS へ逆戻りは致し方ないとして、どうせコンテナを動かすだけだし今更「フツー」の Linux ディストリビューションを使うのも色々面倒なので Container-Optimized OS にしたみた。

Container-Optimized OS の存在は昔から知っていて、できることの制限が厳しいのかと勝手に思っていたけど、Docker を動かすことに限れば「フツー」の Linux ディストリビューションとほとんど遜色ない感じではある。ただそうは言っても完全に同じように使えるというわけではないが、GCP の Container-Optimized OS でサイトを運用するときの tips というページが非常に役立った。

試行錯誤の末に以下のような感じになった。

cloud-init

  • 最初はタダで済む「標準永続ディスク」1 本でインスタンスを立てたけど、あんまりにも遅すぎるので、システム領域およびスワップ用として「バランス永続ディスク」を追加して、「標準永続ディスク」はデータ領域に変更した。これのせいで完全無料ではなくなったけど、多分 ¥ 100 もしないくらいだろうし十分安い
  • Docker のもろもろのファイルの置き場所は「標準永続ディスク」にしたので相変わらず遅いっちゃ遅いけど、ここは我慢することにした
#cloud-config
timezone: Asia/Tokyo

write_files:
- path: /etc/docker/daemon.json
  content: |
    {
            "data-root": "/mnt/disks/docker",
            "live-restore": true,
            "log-driver": "gcplogs",
            "storage-driver": "overlay2",
            "mtu": 1460
    }
- path: /etc/systemd/system/nginx.service
  permissions: 0644
  owner: root
  content: |
    [Unit]
    Description=nginx
    Requires=docker.service

    [Service]
    ExecStart=/usr/bin/docker run -e TZ=Asia/Tokyo --name nginx --network nginx-proxy -p 443:443 --pull always --rm -v /var/docker/nginx/conf.d:/etc/nginx/conf.d -v /var/cache/nginx:/var/cache/nginx -v /var/run:/var/run nginx:stable-alpine
    ExecStop=/usr/bin/docker stop nginx
    ExecStopPost=/usr/bin/docker rm nginx
- path: /etc/systemd/system/tdiary.service
  permissions: 0644
  owner: root
  content: |
    [Unit]
    Description=tDiary
    Requires=docker.service

    [Service]
    ExecStart=/usr/bin/docker run --rm -v /var/docker/tdiary:/var/docker/tdiary -v /var/run/docker.sock:/var/run/docker.sock -w=/var/docker/tdiary docker/compose:1.29.2 up
    ExecStop=/usr/bin/docker run --rm -v /var/docker/tdiary:/var/docker/tdiary -v /var/run/docker.sock:/var/run/docker.sock -w=/var/docker/tdiary docker/compose:1.29.2 down

runcmd:
- systemctl daemon-reload
- systemctl restart docker
- systemctl start tdiary.service
- systemctl start nginx.service

bootcmd:
- swapon /var/swapfile
- fsck.ext4 -tvy /dev/sdb1
- mkdir -p /mnt/disks/docker
- mount -o nosuid,nodev,commit=30,defaults -t ext4 /dev/sdb1 /mnt/disks/docker

tDiary の docker-compose.yml

  • 公式の Docker イメージだと MongoDB が使えない、けど自分でイメージをビルドするのも面倒、ということで command に小細工を仕込んでお茶を濁している
services:
  tdiary:
    image: tdiary/tdiary:${TDIARY_VERSION}
    env_file:
      - ./.env
    command: >
      sh -c '
        echo "gem \"tdiary-io-mongodb\"" >> /usr/src/app/Gemfile.local &&
        echo "gem \"tdiary-cache-memcached\"" >> /usr/src/app/Gemfile.local &&
        curl -o /usr/src/app/tdiary.conf https://raw.githubusercontent.com/tdiary/tdiary-core/v${TDIARY_VERSION}/misc/paas/heroku/tdiary.conf &&
        bundle --path=vendor/bundle --without=development:test --retry=3 &&
        bundle exec rackup'      
    expose:
      - 9292
    networks:
      - default
      - nginx-proxy
    depends_on:
      - memcached
    volumes:
      - ./.htpasswd:/usr/src/app/data/.htpasswd

  memcached:
    image: memcached:1.6.17-alpine
    networks:
      - default

networks:
  default:
    internal: true
  nginx-proxy:
    external: true

.env はこんな感じ。

TDIARY_VERSION=5.2.4
AMAZON_ACCESS_KEY=********
AMAZON_SECRET_KEY=********
MEMCACHE_SERVERS=memcached:11211
MONGODB_URI=mongodb+srv://********
RACK_ENV=production
TZ=Asia/Tokyo

Big thanks to Heroku