LoginSignup
32
35

More than 1 year has passed since last update.

Docker Compose + alpineでサーバー一式を構築する

Last updated at Posted at 2016-04-06

Dokcerコンテナ上に開発環境を作った時の反省点をふまえてやりなおします。

基本方針

  • ConoHaのDockerイメージ上にalpine1をベースにしてサーバーを構築する
  • この記事を分割しないでいいようにシンプルに書く

サーバー作成

ConoHaコントールパネルで「サーバー追加-アプリケーション-Docker」を選択して「追加」ボタン押下。

conoha-docker.png
USキーボードを使っているので「VPS設定 - コンソールキーマップ - en-us」も選択してあります。

# uname -aで確認するとUbuntu14.04.1ベースです。今回はrootで作業します。bashrcにキーマップを登録しておきます。

  • echo loadkeys us >> ~/.bashrc
  • ~/.ssh/authorized_keysに鍵を登録
  • /etc/ssh/sshd_configでパスワード禁止PermitRootLogin without-password
  • ローカルPCのLOCALEがsshで転送されるので日本語ファイルを入れておきます。apt-get install language-pack-ja-base

確認のためローカルのPCからログインし、その後docker-composeをインストールします。

curl -L https://github.com/docker/compose/releases/download/1.6.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

dns

dns/Dockerfile
FROM alpine:latest
RUN apk --update add bind && rm -rf /var/cache/apk/*
EXPOSE 53
CMD ["named", "-c", "/etc/bind/named.conf", "-g", "-u", "named"]

named.confとdbファイルはdocker-compose.yamlでマウントします。

docker-compose.yml
dns:
  container_name: dns
  build: dns
  volumes:
    - "./dns/bind:/etc/bind"
  ports:
    - "53:53"
    - "53:53/udp"

docker-compose.ymlを書いたらdocker-compose up -dで起動します。-dを付けなければフォアグラウンドで起動して出力を見ることが出来ます。これにdocker exec -it dns bashで接続して動作確認します。この後に出てくるコンテナもこの方式で確認していきます。

しかしコンテナ内でnslookup dns.example.com 127.0.0.1しても外部のdnsを見にいってしまいハマりました。alpineで使用しているbusyboxのnslookupにはバグがありserver指定が効かないようです。Dockerホストのnslookupから動作確認しました。
参考:bugs.busybox.net

http

http/Dockerfile
FROM alpine:latest
RUN apk --update add nginx && rm -rf /var/cache/apk/*
RUN chmod 755 /var/lib/nginx /var/lib/nginx/tmp
CMD ["nginx", "-g", "daemon off;"]

無駄にハマったのがapkでnginxを入れた直後は/var/lib/nginxのパーミッションがdrwx------ root rootになっており、リバースプロキシする時に4kb以上のファイルがあると

open() "/var/lib/nginx/tmp/proxy/1/00/0000000001" failed (13: Permission denied) while reading upstream, client:

のようなエラーを吐いてうまくいかないことです。Dockerfileにchmodを書いて解決しました。

docker-compose.yaml
http:
  container_name: http
  build: http
  volumes:
    - "./http/nginx.conf:/etc/nginx/nginx.conf"
    - "./http/conf.d:/etc/nginx/conf.d"
  ports:
    - "80:80"

apkで取得したnginx.confではserver{}の中にlistenが指定されているため、前回のgitbucket/jenkinsの設定は読み込めませんでした。デフォルトからコメント行とlisten行を削除し、conf.dのincludeとuploadサイズの設定を入れたものがこちらです。

nginx.conf
#user  nobody;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    # add
    include /etc/nginx/conf.d/*.conf;
    client_max_body_size 50m;
}

GitBucket

Alpineベースのf99aq8ove/docker-gitbucketを使います。

docker-compose.yml
gitbucket:
  image: "f99aq8ove/gitbucket"
  container_name: gitbucket
  volumes:
    - "./gitbucket/data:/gitbucket"
    - "/etc/localtime:/etc/localtime:ro"
  ports:
    - "8080:8080"

Jenkins

前回はJenkinsコンテナにXvfbやらfirefoxを入れていたのですが、それはJenkinsのスレーブノードにやらせればよさそうなので今回はJenkins単体にします。
参考:Docker ComposeでJenkinsとSelenium Gridを一気に立ち上げる

mkdir -p jenkins/data
chown 1000:1000 jenkins/data
docker-compose.yml
jenkins:
  image: "blacklabelops/jenkins:alpine"
  container_name: jenkins
  volumes:
    - "./jenkins/data:/jenkins"
  ports:
    - "8081:8080"

mail

smtp/pop/imapを一つのコンテナに立てます。docker的には1コンテナ1サービスが原則だと思いますが、特に送信サーバーをスケールする予定もないしどうせrsyslogdもあげるのでまとめてしまいました。

Dockerfile
FROM alpine:latest
RUN apk --update add postfix dovecot rsyslog && rm -rf /var/cache/apk/*

ADD main.cf /etc/postfix/main.cf
ADD valias /etc/postfix/valias
ADD vmailbox /etc/postfix/vmailbox
RUN postmap /etc/postfix/valias
RUN postmap /etc/postfix/vmailbox

ADD 10-auth.conf /etc/dovecot/conf.d/10-auth.conf
ADD 10-mail.conf /etc/dovecot/conf.d/10-mail.conf
ADD auth-passwdfile.conf.ext /etc/dovecot/conf.d/auth-passwdfile.conf.ext

CMD ["sh", "-c", "rsyslogd; postfix start; dovecot; tail -f /dev/null;"]

alpineベースにpostfixとdovecotを入れ、バーチャルホストを使った複数ドメイン対応設定です。

main.cf
mydomain = example.com
inet_interfaces = all
virtual_mailbox_domains = example.com, example.jp
virtual_mailbox_base = /var/spool/mail/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_alias_maps = hash:/etc/postfix/valias
virtual_minimum_uid = 89
virtual_uid_maps = static:89
virtual_gid_maps = static:89
recipient_delimiter = -
valias
alias user@example.com
vmailbox
user@example.com example.com/user
user@example.jp example.jp/user

alpineではデフォルトでuid:89がvpopmailになっています。この権限でバーチャルホスト用のフォルダを用意し読み書きさせます。postfixではdbファイルの作成にpostmapコマンドを実行する必要があるので、DockerfileでRUNさせます。

以下dovecot用設定ファイルです。

10-auth.conf
disable_plaintext_auth = no

gmailからアクセスするのにSSLだと自己署名の証明書が使えないので、plaintextを許可してます。

10-mail.conf
mail_location = maildir:~/
namespace inbox {
  inbox = yes
}
mail_uid = 89
mail_gid = 89
first_valid_uid = 89
first_valid_gid = 89
mbox_write_locks = fcntl

maildirの設定とuidの指定を行います。

auth-passwdfile.conf.ext
passdb {
  driver = passwd-file
  args = /var/spool/mail/vhosts/passwd
}
userdb {
  driver = passwd-file
  args = /var/spool/mail/vhosts/passwd
}
passdb
user@example.com:{CRYPT}xxx::::/var/spool/mail/vhosts/example.com/user:/sbin/nologin

アカウントファイルの設定です。vhostsはpostfixのvirtual_mailbox_baseになっていて、postfixがここに配送したメールをdovecotが受け取ります。

docker-compose.yml
mail:
  container_name: mail
  build: mail
  volumes:
    - "./mail/vhosts:/var/spool/mail/vhosts"
    - "/etc/localtime:/etc/localtime:ro"
  ports:
    - "25:25"
    - "110:110"
    - "143:143"
    - "993:993"
    - "995:995"

まとめ

最終的なdocker-compose.yml

docker-compose.yml
dns:
  container_name: dns
  build: dns
  volumes:
    - "./dns/bind:/etc/bind"
    - "/etc/localtime:/etc/localtime:ro"
  ports:
    - "53:53"
    - "53:53/udp"
http:
  container_name: http
  build: http
  volumes:
    - "./http/nginx.conf:/etc/nginx/nginx.conf"
    - "./http/conf.d:/etc/nginx/conf.d"
    - "./http/public_html:/usr/share/nginx/html"
    - "/etc/localtime:/etc/localtime:ro"
  ports:
    - "80:80"
gitbucket:
  image: "f99aq8ove/gitbucket"
  container_name: gitbucket
  volumes:
    - "./gitbucket/data:/gitbucket"
    - "/etc/localtime:/etc/localtime:ro"
  ports:
    - "8080:8080"
jenkins:
  image: "blacklabelops/jenkins:alpine"
  container_name: jenkins
  volumes:
    - "./jenkins/data:/jenkins"
    - "/etc/localtime:/etc/localtime:ro"
  ports:
    - "8081:8080"
mail:
  container_name: mail
  build: mail
  volumes:
    - "./mail/vhosts:/var/spool/mail/vhosts"
    - "/etc/localtime:/etc/localtime:ro"
  ports:
    - "25:25"
    - "110:110"
    - "143:143"
    - "993:993"
    - "995:995"

自分で立てたサーバーの設定資料としてまとめたのですが、dnsやmailの設定情報をちゃんと載せてないので、後からこの資料だけ見て同じサーバーを立てるのは厳しいですね。

alpineは情報が少ないのと、apkがこなれてなくてデフォルトだとうまく動かないといったことがあり注意が必要です。


  1. 2022/01追記 今は各ディストリビューションがcompactをリリースしてるのでAlpineを使うメリットは少ないです。libc非互換のバグとか踏みたくなければubuntuやdebial-slimでいいでしょう。ubuntu公式で30MiBくらいです。Alpineは5MiBですがライブラリ追加したら誤差の範囲、かな。大量のcontainerを扱うので少しでも小さい方がいい、という場合はAlpineやscratchから作るのもありですね。実行ファイルをstatic linkでコンパイルしてscratchに入れてる記事を見ましたが、それならdockerにしないで実行ファイルのまま配布すればいいのでは?ギャグのつもりなんでしょうけど。 

32
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
35