docker
Ansible
ansible-playbook
alpinelinux

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 ホストに使ってみませんか?情報が少ないため、トラブルの保証は致しかねますが、ぜひ試してみてください!