のほほんおじさんのアウトプット

インフラエンジニア。 マリノス・美術館・編集工学・AWS・ウイスキー・いぶりがっこ・タルタルが好きです。好き勝手やっていこうかなって気持ちです。

Fargateでのコンテナの上書きで大いにハマってしまった、、、

Fargateでのコンテナの上書きについて

  • Fargateでコンテナの上書きをしようと思うと以下の2つができます。

f:id:kothiba:20190520223542p:plain

  • で、ちょっとコンテナの上書きをすることで解決したいなって問題があったので、いろんな事例を調べてみました。結果、Dockerfileの中身を上書きできるんだろうなって結論に至ったわけですが、どうやらそこで今回とんちんかんな認識をしてしまった結果、大いにハマってしまったという経験をしました。
  • 参考にしたのは以下など

解決したい問題

  • Fargateで作成したJMeterコンテナがあって、こいつはシナリオファイルを引数にとるのですが、引数を環境変数として規定して、環境変数を上書きすることで引数にとるシナリオファイルを変更する(違う種類のシナリオを実行する)ようにしたい、というのが今回解決したい問題でした。

    解決前の状況

  • FargateでJMeterコンテナが実行します。
  • Dockerfileには、以下を記載しています。
    • ENTRYPOINTでjmeter.shを実行する
    • CMDで-n -t シナリオファイル
  • 結果的に、jmeter.sh -n -t シナリオファイルというコマンドを実行するコンテナとなり、シナリオファイルに沿った内容のWEBチェックを実行します
FROM alpine:3.9

ARG JMETER_VERSION="5.1.1"
ARG PLUGIN_VERSION="1.4.0" 
ENV JMETER_HOME /opt/apache-jmeter-${JMETER_VERSION}
ENV JMETER_BIN  ${JMETER_HOME}/bin
ENV JMETER_DOWNLOAD_URL  https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${JMETER_VERSION}.tgz
ENV PLUGIN_DOWNLOAD_URL  https://jmeter-plugins.org/downloads/file/JMeterPlugins-Standard-${PLUGIN_VERSION}.zip
ENV SCENARIO_DOWNLOAD_URL [S3に配置したJMeterのシナリオファイル.jmx]

# Install extra packages
ARG TZ="Asia/Tokyo"
RUN    apk update \
    && apk upgrade \
    && apk add ca-certificates \
    && update-ca-certificates \
    && apk add --update openjdk8-jre tzdata curl unzip bash \
    && apk add --no-cache nss \
    && rm -rf /var/cache/apk/* \
    && mkdir -p /tmp/dependencies  \
    && curl -L --silent ${JMETER_DOWNLOAD_URL} >  /tmp/dependencies/apache-jmeter-${JMETER_VERSION}.tgz  \
    && curl -L --silent ${PLUGIN_DOWNLOAD_URL} >  /tmp/dependencies/JMeterPlugins-${PLUGIN_VERSION}.zip  \
    && curl -L --silent ${SCENARIO_DOWNLOAD_URL} >  /tmp/test-plan.jmx  \
    && mkdir -p /opt  \
    && tar -xzf /tmp/dependencies/apache-jmeter-${JMETER_VERSION}.tgz -C /opt  \
    && unzip -oq "/tmp/dependencies/JMeterPlugins-${PLUGIN_VERSION}.zip" -d $JMETER_HOME  \
    && rm -rf /tmp/dependencies  

ENV PATH $PATH:$JMETER_BIN

WORKDIR ${JMETER_HOME}

ENTRYPOINT [ "jmeter.sh" ]
CMD [ "-n" , "-t" , "/tmp/test-plan.jmx" ] 
  • で、シナリオファイルを差し替えて実行したい場合は、上記のDockerfileに記載した内容のENV JMETER_DOWNLOAD_URLをFargateの環境変数の上書きで上書きすればいいだけだと考えたのです。

全然うまくいかないよ、、、

  • でも全然うまくいかない。これはFargateのせいかと考えて色々と調べてみた結果、Fargateの問題ではなく、そもそもDockerfileの書き方が良くないんじゃないかという事に、思い至りました。
  • というか、、、ENV JMETER_DOWNLOAD_URL自体はちゃんと上書きされていた、、、
  • でもそうなると、なぜうまくいかないのか?と思いましたが、以下のように考えると納得できました。
    • ENV JMETER_DOWNLOAD_URLの値自体が上書きされても、DockerRun時に、その次の行以下に記載されているRUN内容が再実行することってないよね?
    • うん。一度Buildされているから、DockerRunするたびにイメージをBuildするなんて意味不明な動きをDockerがすることはないよな。と、、、

一度に2度の作業をするコンテナを作りたい

  • で、そうなってくると今回作ったJMeterのコンテナって、以下の2つのことを一度に実行してくれないと困るってことになります。
    • jmeter.shを実行すること
    • シナリオファイルをダウンロードすること

ならば簡単だ!ENTRYPOINTCMDを複数書けばいい!

  • が、話はそんなに簡単ではありませんでした。
  • まず、CMDはENTRYPOINTの引数のような形で記載しないといけない
    • なので、ENTRYPOINTでjmeter.shを実行しているのに、CMDでcurlを実行しようとするとjmeter.shにはcurlなんてオプションはありませんよって言われる、、、
    • であれば、ENTRYPOINTは使わない!CMDを2個書いてやる!となるのですが、CMDは複数書いても最後に書いた内容しか実行されない、、、
  • やばい、、、どうすればいいんだ??

シェルスクリプト

  • で、このシェルスクリプトをどう書くかっていうのがセンスだよなあって痛感しました。自分はここで相当悩み、助け舟を出してもらい解決策を見出しました。こいうところでサクッとスクリプトを書けるような人間になりたいなあ!!
#!/bin/bash
curl -L --silent $1 > /tmp/test-plan.jmx
jmeter.sh -n -t /tmp/test-plan.jmx
  • $1で第一引数をcurlしてシナリオファイルとして保存します
  • 保存したシナリオファイルをjmeter.sh -n -t /tmp/test-plan.jmxで実行する
  • そして、Dockerfileに以下のように記載してCMDに第一引数となるシナリオファイルの保存先を指定する
COPY run.sh /tmp/
ENTRYPOINT [ "sh" , "/tmp/run.sh" ]
CMD [ "S3上のシナリオファイル" ] 
  • こうすることで、コンテナの上書きであるCMDの上書きを利用してシナリオファイルの引数をいかようにも書き換えられるということになります。

ということで課題クリア!

  • シナリオファイルが複数になった場合の対応は、上記の対応策で解決です。
  • また、JMeterのバージョン変更とか大きな変更のときはビルドし直す必要がありますが、そんなときはイメージにつけるタグで管理します

まとめ

  • Fargateはあくまで実行環境で、実行の大元となるDockerfileを正しく理解することがコンテナを利用する際には必要なんだと感じました。
  • Dockerfileのコマンドの意味が理解できてくると、Fargateってこんなに便利なんだなって理解できるようになりました。
    • 例えば今回のFargateのコンテナの上書き機能として利用したCMDの上書きも、docker上でいうdocker run image名 [CMDの上書き]コマンドと同じ意味で、Dockerで使える機能がAWS上で気軽に使えるっていうのは凄いことなんだなって思いました。