ぽよメモ

レガシーシステム考古学専攻

nginxとdocker-genとその他を使って良い感じにする(1)

jwilder/nginx-proxyという超便利コンテナがあるのですが,こいつは/var/run/docker.sockをReadOnlyとはいえ外側に晒すコンテナにマウントすることになり怖いので,推奨されているようにjwilder/docker-gennginxを分けて同様の環境を構築します.

環境

  • Ubuntu Server 16.04LTS
  • Docker version 1.13.0
  • docker-compose version 1.8.0

構築したい環境

macvlanドライバを用いたフロントのnginxへの静的IPアドレスの割り当て,及びdocker-genとJrCs/docker-letsencrypt-nginx-proxy-companionの機能を用いた各コンテナへのサブドメインの割り当てとSSL対応.(2)でgitlabを立ち上げて完成とします.

前準備

静的アドレス割り当て

まず,うちの環境ではこれまでYAMAHA RTX1200を使って,LXCで構築した外側に晒すコンテナ群のセグメントを分けて運用していました.つまり,それぞれのコンテナに対してブリッジを用いて静的なIPアドレスを割り当てていました.そしてルータのIPマスカレードでそれぞれのコンテナへとパケットを通していました.
しかしDockerで静的なIPを割り当てる方法を検索しても,直接NICの下にぶら下げる方法はあまり出てきませんでした.

そこで先輩に教えていただいたのがdocker networkのmacvlanドライバです.

github.com

これを用いてdocker networkを作り,それぞれのコンテナへとホストに割り当てられているものと同じ空間の静的なipv4アドレスを割り当てることが出来ました.

まず,ホストのNIC(何も使われていない余っているもの.以下hoge)をプロミスキャスモードにし,network createします.

$ docker network create --driver macvlan \
    --subnet=xxx.xxx.x.x/24 \
    --gateway=xxx.xxx.x.y \
    -o parent=hoge dmz_nw

docker-composeでのipの割り当て方は以下の様にします.

version: "2"
services:
  front_test:
    image: nginx
    container_name: front_test
    networks:
      dmz_nw:
        ipv4_address: xxx.xxx.x.z
networks:
  dmz_nw:
    external:
      name: dmz_nw

ブラウザからxxx.xxx.x.zにアクセスしてWelcome to Nginxが出てこれば成功です.

各コンテナを繋ぐネットワークの作製

macvlanドライバを用いると,gateway(ルータ)に直接問い合わせをするためdockerの名前解決は使えない*1ため,docker-genの機能を活用するために別のbridgeドライバを用いたnetworkを作製します*2

$ docker network create --driver bridge \
    -o "com.docker.network.bridge.name"="shared" \
    shared

nginxとdocker-genを組み合わせる

ディレクトリ構造は以下の様にして進めます.

.
├── docker-compose.yml
├──proxy
│   ├── certs
│   ├── conf
│   │   └── default.conf
│   ├── html
│   ├── templates
│   │   └── nginx.tmpl
│   └── vhost
│        └── default
└── web
    └── Dockerfile

nginxの設定

docker-compose.ymlに記述していきます.

version: "2"
services:
  proxy:
    image: nginx
    container_name: proxy # そのままではコンテナ名が面倒なことになるので指定
    volumes:
      - ./proxy/html:/usr/share/nginx/html:rw
      - ./proxy/conf:/etc/nginx/conf.d
      - ./proxy/vhost:/etc/nginx/vhost.d
      - ./proxy/certs:/etc/nginx/certs:ro # ReadOnlyでマウント 
    restart: always
    networks:
      shared:
        aliases:
          - proxy
      dmz_nw:
        ipv4_address: xxx.xxx.x.N
networks:
  shared:
    external:
      name: shared
  dmz_nw:
    external:
      name: dmz_nw

/usr/share/nginx/htmlrwでマウントしないとなぜかJrCs/docker-letsencrypt-nginx-proxy-companionがエラーを吐きました.

docker-genの設定

本来はnginx-proxyに含まれているnginx.tmplファイルが必要となるので落としてきます.

$ curl https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl > ./proxy/templates/nginx.tmpl

nginxの設定に追記していきます.

version: "2"
services:
  proxy:
  # 省略
  nginx-gen:
    image: jwilder/docker-gen:latest
    container_name: nginx-gen
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro # ReadOnlyでマウント
      - ./proxy/templates/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro # tmplファイルをマウント
    volumes_from:
      - proxy
    restart: always
    entrypoint: /usr/local/bin/docker-gen -notify-sighup proxy -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
    networks:
      - shared
networks:
  # 省略 

letsencryptの設定

version: "2"
services:
  proxy:
  # 省略
  nginx-gen:
  # 省略
  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: nginx-letsencrypt
    volumes_from:
      - proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro # ReadOnlyでマウント
      - ./proxy/certs:/etc/nginx/certs:rw
    environment:
      NGINX_DOCKER_GEN_CONTAINER: nginx-gen
    depends_on:
      - nginx-gen
    restart: always
    networks:
      - shared
networks:
  # 省略 

webサーバをぶら下げてみる

以下,webサーバをぶら下げるアドレスをwww.hoge.comとして進めます.

設定

version: "2"
services:
  proxy:
  # 省略
  nginx-gen:
  # 省略
  letsencrypt:
  # 省略
  web:
    build: ./web
    container_name: web
    environment:
      VIRTUAL_HOST: www.hoge.com
      VIRTUAL_NETWORK: shared
      LETSENCRYPT_HOST: www.hoge.com
      LETSENCRYPT_EMAIL: hoge@mail.hoge.com
    depends_on:
      - nginx-gen
      - proxy
    restart: always
    networks:
      - shared
networks:
  # 省略 

webディレクトリ以下のDockerfileを編集しますが,これはgithubリポジトリに自分のwebサーバの静的ファイルを置いているためで必須ではないです.

FROM nginx:latest

RUN apt update && \
    apt install -y git && \
    rm -r /usr/share/nginx/html && \
    git clone https://github.com/pddg/poyo_web.git /usr/share/nginx/html

立ち上げてみる

$ docker-compose up --build

最初letsencryptでの証明書の取得に時間がかかります.うまく立ち上がったっぽい雰囲気を感じたらwww.hoge.comにアクセスしてみて,うまく表示されれば完了です.

まとめ

RTX1200でフィルターを使ってアクセスに制限をかけているとはいえ,macvlan以下にぶら下げたコンテナは何の防御もしていないため,もう少し何かするべきかもしれませんがとりあえずはここまで.
かなり身構えてやり始めましたが,2~3時間で思っていたものが出来上がったので良かったです.

今回は全て同じdocker-compose.ymlに記述しましたが,上記で使用したsharedネットワークにさえ接続すれば,docker runでも,他のdocker-compose.ymlでも,VIRTUAL_HOSTなど各種の環境変数を与えることでサブドメインの割り当てが出来ます.

もう少ししたらgitlabを立ち上げてgitlab.hoge.comへとhttpsでアクセスできるようにした記事を書きたいと思います.

続き書きました

poyo.hatenablog.jp

*1:これは未確認なので実は使えるとかだったら教えてください…

*2:ここに出てくる"com.docker.network.bridge.name"というオプションはホストでbrctl showやifconfig等したときに表示されるインターフェース名を自動生成された名称ではなく,自分で付けた名前にするオプションです.