ElasticBeanstalk Multi-container Docker な環境で、AmazonLinux + httpd + sendmail を動かす方法


ElasticBeanstalk Multi-container Docker な環境で、apache + sendmail を動かす場合、主に sendmail でハマる事があります。

自分が直面した状況

「アプリからメール送ろうとすると固まる!あと、なんかアプリが不安定だなー」

状況1 「アプリからメール送ろうとすると固まる」

  • sendmail は hostname が FQDN じゃないと動かない(固まる)
  • ElasticBeanstalk Multiple Docker 内の hostname は FQDN ではない文字列
  • Dockerfile 内で /etc/hosts を書き換えると、普通の Docker なら上手く動くが、ElasticBeanstalk Multiple Docker では環境が立ち上がらなくなる

状況2 「なんかアプリが不安定」

下記の様に、デーモンを立ち上げて最後に bash をフォアグラウンド起動する方法だと、普通の Docker では問題なく動くが、ECS の Task になると定期的に落ちていた。

ENTRYPOINT service httpd start \
        && service sendmail start \
        && /bin/bash --login

解決方法

  • Dockerfile で Supervisor をインストール。
  • Supervisor で httpd などフォアグラウンド起動できるデーモンを管理。
  • start.sh を作成し、Dockerfile の ENTRYPOINT で叩く。
  • start.sh 内で下記のことをやる
    1. /etc/hosts 書き換え
    2. sendmail などフォアグラウンドで動かせないデーモンを起動
    3. 最後にフォアグラウンドで supervisord 起動。

Dockerfile

FROM amazonlinux:latest

MAINTAINER Your Name

# timezone:Tokyo
RUN cp /etc/localtime /etc/localtime.org\
 && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime\
 && echo -e "ZONE=\"Asia/Tokyo\"\nUTC=false" > /etc/sysconfig/clock

RUN yum install -y httpd24 \
                   sendmail \
                   wget

# Install supervisor and modify it to use python2.6 (not AmazonLinux default python2.7)
RUN wget http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm \
 && rpm -ivh epel-release-6-8.noarch.rpm \
 && yum update -y epel-release \
 && yum --enablerepo=epel install -y supervisor \
 && sed -i -E 's/(^#!\/usr\/bin\/python$)/#!\/usr\/bin\/python26/g' /usr/bin/supervisor*

# conf files
COPY docker_build_files/httpd/conf/httpd.conf /etc/httpd/conf/
COPY docker_build_files/httpd/conf.d/ /etc/httpd/conf.d/
COPY docker_build_files/supervisord/supervisord.conf /etc/

# our application
RUN mkdir /var/app \
 && mkdir /var/app/current
COPY html_app /var/app/current/
RUN chown -R apache /var/app/current/

# update
RUN yum update -y

COPY docker_build_files/script/start.sh /home/
RUN chmod +x /home/start.sh

# start services
ENTRYPOINT /home/start.sh

start.sh

初期状態の /etc/hosts1 から始まる行はプライベートIPしか無いので、その行の後ろにサービスのドメイン名を付ける。
example.comの部分は、適当に読み替えて下さい。

#!/bin/sh

cp /etc/hosts /etc/hosts.orig && cat /etc/hosts.orig | sed -E 's/^(1.+)$/\1 example.com/g' > /etc/hosts

service sendmail start

supervisord --nodaemon

supervisord.conf

[supervisord]
nodaemon=true

[program:httpd]
command=/usr/sbin/httpd -DFOREGROUND
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0