Docker を Alpine Linux で動かそう! (Ansible で環境構築)

はじめに

みなさん、Alpine Linux 使ってますか?

雪餅のインフラ環境では、あらゆるサービスが docker-compose による複数 Docker コンテナの組み合わせにより構築されています。それらのコンテナ内は、 scratchalpine ベースのイメージを多用しているのですが、ホスト OS に何を採用するか長い間悩んでいました。

VPS を効率よく Docker コンテナホストに仕立てあげるために、以下のポイントから Alpine Linux を採用してみた記録です。

  • ディストリビューションに必要なディスク容量が少ない
  • パッケージマネージャが高速でリポジトリのソフトウェアが新しい
  • 常駐サービスが既定で最小限
  • Ansible での環境構築が可能(容易)
  • Docker が公式リポジトリに存在
  • x86-64 と aarch64 で同様に構築可能

Alpine Linux とは

軽量でシンプルな Linux ディストリビューションで、セキュリティを重視した方法でカーネルがビルドされています。

Alpine Linux is an independent, non-commercial, general purpose Linux distribution designed for power users who appreciate security, simplicity and resource efficiency.

About | Alpine Linux より

iso イメージは、 カーネル内のデバイスドライバや同梱されるアプリケーションによって分けられています。 VPS で利用する場合、無駄の少ない VIRTUAL を利用することになると思います。 また、Raspberry Pi 向けのイメージもあります。

インストール

iso イメージからブートし、 root でログインし、 setup-alpine コマンドを利用します。ウィザードにしたがえば、ものの 2 分ほどでインストールは終わります。

環境構築

Alpine Linux は、パッケージ管理に apk, init に OpenRC, libc に musl-libc を採用しています。init と libc はあまり一般的でないものですが、リポジトリが比較的豊富なのでインストールやビルドが必要になって困ることは少ないでしょう。また、apkyumapt よりもきわめて高速で、依存関係の解決がシンプルです。

python のインストール

Ansible でセットアップするために python は手動で入れておきます。

apk add python

Ansible で環境構築する。

Alpine で Ansible playbook するときのポイント

  • Alpine Linux のはまりポイントを避けるためのパッケージ群
    • coreutils - GNU 製の utils。 Alpine Linux でコマンドを提供する busybox は仕様が異なり、Ansible の各種 module と互換性がないことが多いため。
    • curl - get_url module を使いたい場合は入れておく。
    • shadow - useradd などのユーザー操作系の多くのコマンドを Alpine Linux で利用できるようにする。 user module を使いたい場合は入れておく。
    • docker - Alpine Linux の Community Repository からは、比較的新しい Docker を利用できるのでそのまま使います。
    • py-pip - docker-composepip module でインストールするために入れておきます。docker-compose 公式で提供されている pyInstall 版のシングルバイナリは、 glibc 向けにビルドされており使えません。

playbook 例

  • basic.yml (環境構築)
tasks: 
  - 
    lineinfile: 
      line: "http://dl-cdn.alpinelinux.org/alpine/v3.8/community"
      path: /etc/apk/repositories
      state: present
    name: "Community ベースのリポジトリを有効にします。"
  - 
    apk: 
      name: "python,py-pip,sudo,coreutils,curl,git,htop,rsync,shadow,docker"
      state: present
      update_cache: true
    name: "パッケージの導入 python py-pip sudo coreutils curl git htop rsync shadow docker"
  - 
    name: "{{ username }} ユーザーを作成し、 wheel グループに所属させる。"
    user: 
      append: true
      groups: wheel
      home: "/home/{{ username }}"
      name: "{{ username }}"
      password: hogefuga
      shell: /bin/sh
      uid: 1000
  - 
    authorized_key: 
      key: "{{ item }}"
      state: present
      user: "{{ username }}"
    name: "{{ username }} に SSH 公開鍵を登録する。"
    with_file: 
      - public_keys/hogefuga.pub
  - 
    lineinfile: 
      backrefs: true
      line: "%wheel ALL=(ALL) NOPASSWD: ALL"
      path: /etc/sudoers
      regexp: "^#?\\s%wheel ALL\\=\\(ALL\\) NOPASSWD"
      state: present
    name: "パスワードなし sudo を wheel に許可させる。"
  - 
    lineinfile: 
      backrefs: true
      dest: /etc/ssh/sshd_config
      line: "{{ item.line }}"
      regexp: "{{ item.regexp }}"
      state: present
    name: "sshd_config を編集する。"
    notify: 
      - "restart sshd"
    with_items: 
      - 
        line: "PermitRootLogin prohibit-password"
        regexp: "^#?\\s*PermitRootLogin"
      - 
        line: "PasswordAuthentication no"
        regexp: "^#?\\s*PasswordAuthentication yes"
      - 
        line: "PubkeyAuthentication yes"
        regexp: "^#?\\s*PubkeyAuthentication"
  - 
    name: "dockerd を有効化させる。"
    service: 
      enabled: true
      name: docker
      state: started
  - 
    name: "docker-compose をインストールする。"
    pip: 
      name: docker-compose
handlers: 
  - 
    name: "sshd の再起動をする。"
    service: 
      enabled: true
      name: sshd
      state: restarted

mackerel-agent を使う

監視として mackerel-agent を使う場合、公式で公開されているバイナリは glibc 向けにビルドされているため動きません。

静的ビルドされた mackerel-agent を得るには、 Windows で 環境変数 GOOS=linux, GOARCH=amd64 or GOARCH=arm64 を与えて、 go get github.com/mackerelio/mackerel-agent するのが一番簡単だと思います。

OpenRC 向けの init スクリプトも必要となります。

playbook 例

  • openrc-init/mackerel-agent
#!/sbin/openrc-run
# Copyright 2014 Shota Fukumori (sora_h) <her@sorah.jp>
# Distributed under the terms of the MIT License
# $Header: $

LOGFILE=${LOGFILE:-/var/log/mackerel-agent.log}
pidfile=${PIDFILE:-/var/run/mackerel-agent.pid}
CONFIG=${CONFIG:-/etc/mackerel-agent/mackerel-agent.conf}
ROOT=${ROOT:-/var/lib/mackerel-agent}

if [ -n "$BASIC" ]; then
  APIBASE=${APIBASE:="https://${BASIC}@mackerel.io"}
else
  APIBASE=${APIBASE:="https://mackerel.io"}
fi

command=/usr/bin/mackerel-agent
command_args="--apibase=$APIBASE --conf=$CONFIG --pidfile=$pidfile"
command_background=true
start_stop_daemon_args="-1 ${LOGFILE} -2 ${LOGFILE}"

base : https://github.com/sorah/sorah-overlay/blob/master/net-analyzer/mackerel-agent/mackerel-agent-0.6.1.1.ebuild

  • amd64-bin/mackerel-agent

amd64 向け静的ビルド mackerel-agent バイナリ

  • amd64-bin/mackerel-agent

arm64 向け静的ビルド mackerel-agent バイナリ

  • mackerel-agent.yml
tasks: 
  - 
    copy: 
      dest: /usr/bin/mackerel-agent
      mode: 493
      src: amd64-bin/mackerel-agent
    name: "mackerel-agent static をインストールする。"
  - 
    name: "mackerel-agent config の存在確認を行う。"
    register: _mackerel_conf
    stat: 
      path: /etc/mackerel-agent/mackerel-agent.conf
  - 
    file: 
      mode: 493
      path: /etc/mackerel-agent
      state: directory
    when: "not _mackerel_conf.stat.exists"
  - 
    file: 
      mode: 420
      path: /etc/mackerel-agent/mackerel-agent.conf
      state: touch
    when: "not _mackerel_conf.stat.exists"
  - 
    command: "/usr/bin/mackerel-agent init -apikey <Your Mackerel API key>"
    name: "mackerel-agent conf の初期化を行う。"
    when: "not _mackerel_conf.stat.exists"
  - 
    copy: 
      dest: /etc/init.d/mackerel-agent
      mode: 493
      src: openrc-init/mackerel-agent
    name: "mackerel-agent の OpenRC 向け init スクリプトを設定する。"
  - 
    name: "mackerel-agent を有効化する。"
    service: 
      enabled: true
      name: mackerel-agent
      state: started

評価

最小環境のディスク利用量

格安 VPS の一つ Vultr では、カスタム iso インストールで Alpine Linux をサポートしています。この環境へインストールした際の ディスク・メモリ使用量を記したものが以下の通りです。

  • Vultr 1-CPU 512MB-RAM 20GB-SSD での検証

    • インストール直後

      • 実行中のプロセス (参考)
      PID   USER     TIME  COMMAND
      1 root      0:00 /sbin/init
      1845 root      0:00 udhcpc -b -p /var/run/udhcpc.eth0.pid -i eth0 -x hostname:localhost
      1917 root      0:00 /sbin/syslogd -Z
      1971 root      0:00 /sbin/acpid
      2000 chrony    0:00 /usr/sbin/chronyd -f /etc/chrony/chrony.conf
      2027 root      0:00 /usr/sbin/crond -c /etc/crontabs
      2059 root      0:00 /usr/sbin/sshd
      2063 root      0:00 /sbin/getty 38400 tty1
      2064 root      0:00 /sbin/getty 38400 tty2
      2067 root      0:00 /sbin/getty 38400 tty3
      2069 root      0:00 /sbin/getty 38400 tty4
      2072 root      0:00 /sbin/getty 38400 tty5
      2076 root      0:00 /sbin/getty 38400 tty6
      2120 root      0:00 /usr/lib/ssh/sftp-server
      
      • ディスク使用量
      Filesystem                Size      Used Available Use% Mounted on
      /dev/vda1                92.8M     12.6M     73.3M  15% /boot
      /dev/vda3                18.5G    112.8M     17.4G   1% /
      
    • mackerel-agent まで導入

      • ディスク使用量
      Filesystem      Size  Used Avail Use% Mounted on
      /dev/vda1        93M   13M   74M  15% /boot
      /dev/vda3        19G  388M   18G   3% /
      

ディスク使用量は、Docker インストール済みの状態で 388MB に収まります。これによって、 VPS のディスクを最大限にアプリケーションに使うことができ、コストを抑えられます。

Mastodon Worker の運用事例 (メモリ使用量)

Vultr 1-CPU 2048MB-RAM 40GB-SSD において、Mastodon on debian w/ jemalloc 5.1.0 の Docker コンテナ Sidekiq (並行数設定 50) を 4 コンテナ実行していた環境でのメモリ利用量です。

  • CoreOS Beta 1939.2.1 利用時

    約 1.55 GB

    CoreOS Memory Usage

  • Alpine Linux 3.8.1 利用時

    約 1.15 GB

    Alpine Linux Memory Usage

原因はわかっていませんが、 CoreOS 1939.2.1 環境と比較して 400MB ほどメモリ利用量を抑えることができています。

その他

Scaleway について

Scaleway で Alpine Linux を使う場合、 x86-64 であれば公式のイメージ選択から選ぶことができます。ARM64 の場合は、 scaleway/image-builderscaleway/image-alpine を用いて DockerHub の alpine:3.8 を Scaleway 用のイメージに変換することができます。

感想

今回、 CoreOS をベースにしていたすべての環境を Alpine Linux に置き換えました。もともと、 k8s の導入が見送りになっていたために、 CoreOS は無駄に不便を強いる存在になっていたということでもあります。 Alpine Linux は、もともと入っているパッケージが少なく、 apk も高速であるため Ansible で様々な VPS を跨いで管理するにも楽で良いなと思っています。 みなさんもぜひ、 Alpine Linux を Docker ホストに使ってみませんか?情報が少ないため、トラブルの保証は致しかねますが、ぜひ試してみてください!