LoginSignup
182
216

More than 5 years have passed since last update.

1台のサーバ上にDockerを使って複数サービス運用してみる

Last updated at Posted at 2016-07-08

Dockerを使ってProductionを運用してみて数ヶ月。
以下の様な構成で(今のところ)安定して動いているので、備忘録としてまとめておきます。
DBのコンテナ化も考えましたが、データ永続化の面などでちょっと不安だったのでやめました。

なぜDockerを選択したか

まず背景として、大人の事情で1台のサーバ上に複数サービスを運用する必要がありました。
ApacheやTomcatを、別インスタンスで稼働させる手も考えましたが、
将来の移行コストやポート番号の管理問題もあり、Dockerを選択しました。
(というか、これならDockerでいけそう。やってみたい!というモチベーションがあったのが大きいです)

前提

  • serviceA、serviceBをサーバ1台で運用
  • serviceA、serviceBで同じデータベースを参照
  • ドメイン部分は固定(ここではhoge.jpとする)。サブドメインを分けて、複数サービスを運用
    • serviceA -> https://serviceA.hoge.jp/....
    • serviceB -> https://serviceB.hoge.jp/....
  • SSL通信
  • serviceAをバージョンアップする際、serviceBは停止しないようにする(逆も同じ)

構成

Network diagram.png

nginx

  • 役割
    • リバースプロキシ
    • serviceAに対するリクエストはlocalhost:49998へ、serviceBに対するリクエストはlocalhost:49999へ振り分けます
      • 49998や49999は空いているポート番号の例です。適当に変えて下さい。
    • SSLを解き、以降(サーバ内)の通信はhttpとします
    • httpアクセスはhttpsにリダイレクトさせます
  • 設定ファイルの内容↓

    ### serviceA ###
    server {
        listen 80;
        server_name serviceA.hoge.jp;
        location / {
            rewrite ^(.*)$ https://$host$1 permanent;
        }
    }
    server {
        listen 443;
        server_name serviceA.hoge.jp;
        ssl on;
        ssl_certificate {serviceAのSSLサーバ証明書パス};
        ssl_certificate_key {秘密鍵パス};
    
        location / {
            # 49998は後述のdockerコンテナのポート番号
            proxy_pass http://localhost:49998;
            proxy_redirect http:// https://;
            # 接続元情報を維持
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
    
    ### serviceB ###
    server {
        listen 80;
        server_name serviceB.hoge.jp;
        location / {
            rewrite ^(.*)$ https://$host$1 permanent;
        }
    }
    server {
        listen 443;
        server_name serviceB.hoge.jp;
        ssl on;
        ssl_certificate {serviceBのSSLサーバ証明書パス};
        ssl_certificate_key {秘密鍵パス};
    
        location / {
            # 49999は後述のdockerコンテナのポート番号
            proxy_pass http://localhost:49999;
            proxy_redirect http:// https://;
            # 接続元情報を維持
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
    

docker-compose

  • サービス毎にコンテナの管理や起動・停止など行いたかったので、"docker-compose"を使用しています
  • serviceAのdocker-compose.yml

    # tomcat
    tomcat:
      build: tomcat
      container_name: serviceA-tomcat
      stdin_open: true
      tty: true
      volumes:
        - /etc/localtime:/etc/localtime:ro
        - /var/log/docker-container/serviceA/tomcat:/var/log/tomcat8:rw
      extra_hosts:
        - "docker-host:${DOCKER_HOSTIP}"
    
    # apache
    apache:
      build: apache
      container_name: serviceA-apache
      stdin_open: true
      tty: true
      volumes:
        - /etc/localtime:/etc/localtime:ro
        - /var/log/docker-container/serviceA/apache:/var/log/apache2:rw
      links:
        - tomcat
      ports:
        - "49998:80"
    
  • ポイント

    • extra_hostsの設定では、"docker-host"という名前でコンテナからホストを参照できるようにしています

      • ${DOCKER_HOSTIP}は、以下シェルのワンライナーで取得してホストの環境変数に設定してあります

        $ ip route show | grep docker0 | awk \"{print \\\$9}\"
        
    • 49998でポートを公開しています。nginxのserviceA設定で指定するポート番号になります

    • volumesでは、タイムゾーンとログ出力ディレクトリをマウントしています

  • serviceBのdocker-compose.ymlも上記と同様に作成します。違いはservice名(A->B)とports部分(49998->49999)になります

dockerコンテナ(Ubuntu15.10)

  • serviceA-Apache

    • DockerFile

      FROM ubuntu:15.10
      
      MAINTAINER xxx <xxx@xxxx.xx>
      
      RUN rm -rf /var/lib/apt/lists/* && \
          apt-get clean && \
          apt-get update && \
          apt-get install -y apache2 \
                             vim \
                             less \
                             net-tools \
                             nmap \
                             curl \
                             nkf \
                             inetutils-ping
      
      COPY serviceA-apache.conf /etc/apache2/sites-available/
      
      RUN a2ensite serviceA-apache.conf && \
          a2enmod proxy proxy_http rewrite
      
      ## set locale
      RUN locale-gen ja_JP.UTF-8
      ENV LANG ja_JP.UTF-8
      ENV LANGUAGE ja_JP:en
      ENV LC_ALL ja_JP.UTF-8
      
      EXPOSE 80
      
      ENV APACHE_RUN_USER    www-data
      ENV APACHE_RUN_GROUP   www-data
      ENV APACHE_PID_FILE    /var/run/apache2.pid
      ENV APACHE_RUN_DIR     /var/run/apache2
      ENV APACHE_LOCK_DIR    /var/lock/apache2
      ENV APACHE_LOG_DIR     /var/log/apache2
      
      ## tail -f ... はコンテナが途中終了しないためのおまじない命令
      ENTRYPOINT service apache2 start && tail -f /dev/null
      
    • serviceA-apache.conf(docker-composeでlinkさせているtomcatコンテナへリクエストを投げます)

          .
          .
      <Location />
          ProxyPass http://serviceA-tomcat:8080/
      </Location>
          .
          .
      
  • serviceA-Tomcat

    • DockerFile

      FROM ubuntu:15.10
      
      MAINTAINER xxx <xxx@xxxx.xx>
      
      RUN rm -rf /var/lib/apt/lists/* && \
          apt-get clean && \
          apt-get update && \
          apt-get -y upgrade && \
          apt-get install -y vim \
                             less \
                             net-tools \
                             nmap \
                             curl \
                             nkf \
                             inetutils-ping
      
      ## java8,tomcat8
      ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
      RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
          apt-get install -y software-properties-common && \
          add-apt-repository -y ppa:webupd8team/java && \
          apt-get update && \
          apt-get install -y oracle-java8-installer \
                             tomcat8
      ENV PATH $PATH:$JAVA_HOME/bin
      
      ## set locale
      RUN locale-gen ja_JP.UTF-8
      ENV LANG ja_JP.UTF-8
      ENV LANGUAGE ja_JP:en
      ENV LC_ALL ja_JP.UTF-8
      
      ## tomcat
      ENV CATALINA_HOME /usr/share/tomcat8
      ENV CATALINA_BASE /var/lib/tomcat8
      
      RUN mkdir -p $CATALINA_BASE/bin && \
          chown -R tomcat8:tomcat8 $CATALINA_BASE/bin
      
      RUN mkdir -p $CATALINA_HOME/common/classes && \
          mkdir -p $CATALINA_HOME/server/classes && \
          mkdir -p $CATALINA_HOME/shared/classes && \
          mkdir -p $CATALINA_HOME/temp && \
          rm -rf $CATALINA_BASE/common && \
          rm -rf $CATALINA_BASE/server && \
          rm -rf $CATALINA_BASE/shared && \
          rm -rf $CATALINA_BASE/temp && \
          rm -rf $CATALINA_BASE/webapps/ROOT && \
          ln -s $CATALINA_HOME/common $CATALINA_BASE/common && \
          ln -s $CATALINA_HOME/server $CATALINA_BASE/server && \
          ln -s $CATALINA_HOME/shared $CATALINA_BASE/shared && \
          ln -s $CATALINA_HOME/temp $CATALINA_BASE/temp
      
      EXPOSE 8080
      
      ## tail -f ... はコンテナが途中終了しないためのおまじない命令
      ENTRYPOINT $CATALINA_HOME/bin/startup.sh && tail -f /dev/null
      
  • serviceB-Apache

    • 上記と同様に作成
  • serviceB-Tomcat

    • 上記と同様に作成

postgreSQL

  • コンテナからpostgreSQLへの接続方法は以下になります(JDBC接続、ポート5432の場合)

    jdbc:postgresql://docker-host:5432/
    
  • "docker-host"はdocker-composeのextra_hostsで設定しています

サービス起動

$ cd {docker-compose.ymlがあるディレクトリ}
$ docker-compose up -d

DevOps

  • 本サービスでは以下ツールを使用しています。この辺りの詳細は後日また書こうと思ってます。
    • Itamae(プロビジョニング)
    • Jenkins(CI)
    • Fablic(デプロイ)
    • idobata(チャット)
    • Flyway(DBマイグレーション)

まとめ

パフォーマンスや障害発生時の切り分けなど、不安だった点はいくつかありましたが、
現状それに関しても問題なく運用出来ています。
運用・開発者がDockerに関する知識を最低限持つ必要がありますが、結果Dockerで構築してみて良かったと思ってます。
サービスによっては、インフラ構築の際の有力な選択肢としてDockerを加えてもいいと感じています。

追記(2017/01/25)

  • 本番運用していて少し困ったこと
    • yumやaptのパッケージアップデート時にDockerに更新がかかった場合、Dockerコンテナが停止してしまいます
    • パッケージアップデートでDockerを除外してしまうと、カーネルが更新された時とか不具合起こしそうだからやめた方がよさそう(Dockerはホストとコンテナでカーネルが共有されている)
182
216
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
182
216