【詰まった】CakePHPにAWS SDK for PHPを導入する方法〜仕事あるある〜

‘AwsS3S3Client’ not foundの呪縛から解放するには…

 

ある案件で、すでにCakePHPで作られた管理画面があった。
(※この案件でCakePHPを初めて使うことになる)

そこに画像をアップロードする機能があったんだけど、プロジェクトが大きくなるにつれてAWSに以降することになった。

そのため、画像アップロードの向き先をローカルではなく、S3に以降しようと話がまとまった。

そんなときに起きたあるある話をまとめますた。

環境

 
・ CakePHP v2.5.4
・ AWS SDK for PHP v2.8
・ composer/installers v~1.0

 

途中から知るComposerについて

 
最初にやったことは、AWS SDK for PHP(aws-sdk-php)をAWS公式からダウンロード。
 
CakePHPの場合、GITで管理されているプラグインに関しては、cakephp/app/Plugin直下で管理し、ライブラリ/モジュールなどcakephp/app/Vendorで管理されることが作業中わかったので、ダウンロードしたaws-sdk-phpのzipをVendorの中で解答(zipファイルは消す)。
 
そして参考記事で紹介されている内容をもとにaws-sdk-phpの中に入っているS3Clientを使うと…

2017-04-24 20:12:18 Error: Fatal Error (1): Class 'AwsS3S3Client' not found in [/opt/www/cakephp/app/Plugin/AmazonWebServices/Model/Datasource/S3.php, line 24]

 
とエラーが出て、

use AwsS3S3Client;

ここの呼び出しがちゃんと処理されていないらしい。

参考記事 

CakePHPのDatasourceを使ってAWS S3にファイルをアップロードする
CakePHP2.3でAWS SDK2 for PHPを使ってS3にファイルをアップロードする方法
 

‘AwsS3S3Client’ not foundの対策

手動でaws-sdk-phpを入れたが、Composerで導入する。

 
AWS SDK for PHPをインストールするならComposerでしょ!の記事の内容を見て、
AWSの公式ドキュメントCakePHPの公式ドキュメントを確認。

Composerについて

 
元々、FuelPHPでComposerを使っていたこととaws-sdk-phpをComposerから導入したので、フレームワークは違うがすでにComposerでaws-sdk-phpを入れていたFuelPHPのプロジェクトを見ながら作業を再開。
 
次に詰まったのは、Composerで入れても‘AwsS3S3Client’ not foundが起きてしまう。
再度、ドキュメントを確認していくとComposerで入れた時に自動的に生成された、autoload.phpを読み込みが必要だが、それまでのCakePHPのプロジェクトでは、そもそもautoload.phpがなかったため、インポート処理もなかった。
 

autoload.phpを読み込み

 
ドキュメントを確認すると

bootstrap.phpに

require APP . ‘Vendor/autoload.php’;

を追加することがわかった。

Vendorにもcomposerを入れる

また、composer.jsonのrequire内に

“composer/installers”: “~1.0”

を追加する。
 
 
これは、autoload.phpが使うようだ。
composer/installersがないと、また違うエラーが出てしまう。

結果

これらの設定で、‘AwsS3S3Client’ not foundの呪縛から解放された。
 
他にこれらが書かれている記事がなかったのと、社内共有のためにまとめました。
 
お役にたたてもらえばと存じまする〜。

 

続きを読む

Elastic Beanstalkトラブルシューティング集

公式のトラブルシューティングに載ってないものをまとめてみました。
いろいろハマった気もしますが、覚えているやつだけ記載しています。

と、その前に

基本的なデバッグ方法としては以下の通りです。

  1. eb create をするときに –debug をつける
  2. eb ssh して直接インスタンスの中を確認する
  3. eb logs する

インスタンスが生成できていなければ 1. 、インスタンスが生成できていれば 2. 、pingで疎通できれば 3. で探っていく感じになります。

Q1. Application Load Balancer を選択するとエラーになる

eb create するときに Select a load balancer type で application を選択すると、こんな感じのエラーが出る。

eb : Configuration validation exception: Invalid option value: 'null' (Namespace: 'aws:ec2:vpc', OptionName: 'Subnets'): Specify the subnets for the VPC for load balancer type application.

A1. コマンドオプションで指定する

VPC が複数ある環境の場合、Elastic Beanstalk がどの VPC を選んだらいいか判断できないようで、このエラーが発生するみたいです。
なので、 eb create のコマンドオプションで VPC 関連の情報を指定すれば OK です。

eb create xxxxxxxx \
    --elb-type application \
    --vpc.id vpc-xxxxxxxx \
    --vpc.elbsubnets subnet-xxxxxxxx,subnet-xxxxxxxx \
    --vpc.ec2subnets subnet-xxxxxxxx,subnet-xxxxxxxx \
    --vpc.elbpublic \
    --vpc.publicip

Q2. リソースが作成できない

以下のようなエラーが出てリソースの作成に失敗する。

Stack named 'awseb-e-xxxxxxxxxx-stack' aborted operation. Current state: 'CREATE_FAILED' Reason: The following resource(s) failed to create: [ALB, AWSEBV2LoadBalancerTargetGroup, AWSEBBeanstalkMetadata, AWSEBLoadBalancerSecurityGroup].

A2. 権限を付与する

実行ユーザーに AWSElasticBeanstalkFullAccess というポリシーをアタッチすれば OK です。
ここでいう実行ユーザーとは ~/.aws/config で指定している IAM ユーザーのことです。

Q3. composer / bundler などで落ちる

hooks/appdeploy/pre にある shell を実行するタイミングで落ちる。
例えばこんなエラーです。

/var/log/eb-activity.log を見てもだいたい解決しないのはお約束です。

ERROR: [Instance: i-xxxxxxxx] Command failed on instance. Return code: 1 Output: [CMD-AppDeploy/AppDeployStage0/AppDeployPreHook/10_composer_install.sh] command failed with error code 1: /opt/elasticbeanstalk/hooks/appdeploy/pre/10_composer_install.sh
++ /opt/elasticbeanstalk/bin/get-config container -k app_staging_dir
+ EB_APP_STAGING_DIR=/var/app/ondeck
+ cd /var/app/ondeck
+ '[' -f composer.json ']'
+ export COMPOSER_HOME=/root
+ COMPOSER_HOME=/root
+ '[' -d vendor ']'
++ /opt/elasticbeanstalk/bin/get-config optionsettings -n aws:elasticbeanstalk:container:php:phpini -o composer_options
+ PHP_COMPOSER_OPTIONS=--no-dev
+ echo 'Found composer.json file. Attempting to install vendors.'
Found composer.json file. Attempting to install vendors.
+ composer.phar install --no-ansi --no-interaction --no-dev

なんとかかんとか

Hook //opt/elasticbeanstalk/hooks/appdeploy/pre/10_composer_install.sh failed. For more detail, check /var/log/eb-activity.log using console or EB CLI.

この場合は出ているエラーのうち、なんとかかんとかの部分で判断できます。

A3-1. Cannot allocate memory

Cannot allocate memory と出ているなら composer の実行時にメモリが足りていない可能性が高いので、.ebextensions でメモリを増やす設定を追加します。

.ebextensions
option_settings:
  aws:elasticbeanstalk:container:php:phpini:
    memory_limit: 1024M

インスタンスを大きくするとかできるなら楽ちんです。
(swap ファイル作るでも解決できるはずだが調べてない)

A3-2. ErrorException

[ErrorException] Undefined index: hash

ERROR: bundle install failed!
の場合、lock ファイルおかしい可能性があります。

eb ssh をしてみて、lock ファイルを消してライブラリをインストールすると分かったりします。

# ruby なら
cd /var/app/ondeck/
sudo rm Gemfile.lock
bundle install

# php なら
cd /var/app/ondeck/
sudo rm composer.lock
composer.phar install

僕の場合は composer 自体のバージョンがローカル環境とあっていないためにエラーになっていました。
なので、.ebextensions でバージョンを指定して対応しました。

.ebextensions
commands:
  01updateComposer:
    command: export HOME=/root && /usr/bin/composer.phar self-update 1.5-dev

Q4. DB に繋がらない

エラーログをみると DB に繋げないっていうのです。

A4. ローカル IP からのアクセスを変更する

原因としては Application Load Balancer を選択したせいで subnet の IPv4 CIDR が複数のブロックになった可能性が疑われます。

なので、MySQL にログインして該当のブロックアドレスに GRANT してあげれば OK です。

use mysql;
SELECT Host, User, Password, Select_priv, Insert_priv,Update_priv, Delete_priv FROM user; -- 権限を調べてみる

GRANT ALL PRIVILEGES ON database.* to hoge@"ブロックアドレス%" IDENTIFIED BY 'password' WITH GRANT OPTION;

Q5. 環境を削除しても消えない

Elastic Beanstalk のイベントでこんな感じになって環境が消せないという症状です。

The environment termination step failed because at least one of the environment termination workflows failed.

A5. 問い合わせたら消してくれるっぽい

まあ影響ないし置いといたらいいんじゃないかな。。。

続きを読む

ECSにZabbix環境をデプロイする【cloudpack大阪ブログ】

cloudpack大阪の佐々木です。
Zabbix環境をコンテナとしてECS上につくってみたので、まとめときます。

デプロイ方法

ecs-cliとdocker-compose使ってデプロイします。

基本的なやり方はこちら
http://qiita.com/taishin/items/076a7699c787da68e396

docker-coposeはv2が使えるらしいので、今回はv2で記述しています。
http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/cmd-ecs-cli-compose.html

Amazon ECS CLI の最新バージョンでは、Docker 構成ファイル構文のバージョン 1 と 2 がサポートされています。

v2のリファレンス
https://docs.docker.com/compose/compose-file/compose-file-v2/

docker-compose.yml

docker-compose.yml
version: '2'

services:
  mysql-server:
    image: mysql
    mem_limit: 268435456
    environment:
      - MYSQL_DATABASE=zabbix
      - MYSQL_USER=zabbix
      - MYSQL_PASSWORD=zabbix
      - MYSQL_ROOT_PASSWORD=zabbix
    volumes:
        - /ecs/zabbix_mysql:/var/lib/mysql
    logging:
      driver: awslogs
      options:
        awslogs-group: "ECS-zabbix"
        awslogs-region: "us-east-1"
        awslogs-stream-prefix: "zabbix"

  zabbix-server-mysql:
    image: zabbix/zabbix-server-mysql:ubuntu-3.2-latest
    mem_limit: 134217728
    environment:
      - DB_SERVER_HOST=mysql-server
      - MYSQL_USER=zabbix
      - MYSQL_PASSWORD=zabbix
      - MYSQL_DATABASE=zabbix
    logging:
      driver: awslogs
      options:
        awslogs-group: "ECS-zabbix"
        awslogs-region: "us-east-1"
        awslogs-stream-prefix: "zabbix"
    links:
      - mysql-server
    ports:
      - 10050:10050

  zabbix-web-nginx-mysql:
    image: taishin/zabbix-web:latest
    mem_limit: 134217728
    environment:
      - DB_SERVER_HOST=mysql-server
      - ZBX_SERVER_HOST=zabbix-server-mysql
      - MYSQL_USER=zabbix
      - MYSQL_PASSWORD=zabbix
      - MYSQL_DATABASE=zabbix
      - TZ=Asia/Tokyo
      - COMPOSE_HTTP_TIMEOUT=200
    logging:
      driver: awslogs
      options:
        awslogs-group: "ECS-zabbix"
        awslogs-region: "us-east-1"
        awslogs-stream-prefix: "zabbix"
    links:
      - mysql-server
      - zabbix-server-mysql
    ports:
      - 8090:80

順番に説明します。

コンテナ

下記の3つで構成するようにしました。
– mysql
– zabbix-server
– zabbix-web

Zabbixのコンテナはこちらのを使用します。
https://hub.docker.com/u/zabbix/

zabbix-webはそのまま使うとグラフの日本語が文字化けしますので、日本語フォントを入れて、Buildします。
Dokcerfileは下記のようになります。

FROM zabbix/zabbix-web-nginx-mysql:ubuntu-3.2-latest
RUN apt-get update -y && apt-get install -y fonts-ipafont
RUN ln -s /usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf /usr/share/zabbix/fonts/ipagp.ttf
RUN sed -i -e 's/graphfont/ipagp/g' /usr/share/zabbix/include/defines.inc.php

ecs-cliで使うdocker-composeはbuildに対応していないので、あらかじめビルドしてどこかにアップしておく必要があります。
http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/cmd-ecs-cli-compose.html

重要
build ディレクティブは現在サポートされていません。

今回は自分のdockerhubにアップしておきました。

メモリ制限

メモリ制限は下記に記述でハード制限ができます。ソフト制限はできないっぽいです。

    mem_limit: 268435456

永続化データ

MySQLのデータは永続化したいので、ボリュームを作成します。
下記の記述でホストOSの/etc/zabbix_mysqlがコンテナの/var/lib/mysqlにマウントされます。

    volumes:
        - /ecs/zabbix_mysql:/var/lib/mysql

マネジメントコンソールで見るとこんな感じです。

Kobito.NcjJB2.png

Kobito.dg0AbK.png

amazon-ecs-optimizedのAMIを使う場合は下記も注意です。
http://qiita.com/taishin/items/cff9c3212d0f697653e4

Log

コンテナが出力するログはCloudwatch Logsに転送します。
http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/using_awslogs.html

docker-compose v1のときは

log_driver: awslogs

こんな記述でしたが、v2では下記のような表記になります。

    logging:
      driver: awslogs
      options:
        awslogs-group: "ECS-zabbix"
        awslogs-region: "us-east-1"
        awslogs-stream-prefix: "zabbix"

ロググループはあらかじめ作成しておく必要があります。

ストリームプレフィックスですが、

  • awslogs-stream-prefix をつけない場合

Kobito.V9TWgn.png

コンテナごとに乱数のストリーム名になります。

  • awslogs-stream-prefix をつけた場合
    Kobito.GSxPru.png

ストリーム名が下記のフォーマットになるので、付けておいた方が分かりやすいです。

prefix-name/container-name/ecs-task-id

ポート

ホストの8090番ポートをコンテナの80番ポートに転送しています。

    ports:
      - 8090:80

ちなみに固定ポートではなく、ダイナミックポートにする場合は下記のように書きます。

    ports:
      - :80

デプロイ

ecs-cli compose service up です。

$ ecs-cli compose service up                                                  [10:47:02]
WARN[0000] Skipping unsupported YAML option...           option name=networks
WARN[0000] Skipping unsupported YAML option for service...  option name=networks service name=zabbix-server-mysql
WARN[0000] Skipping unsupported YAML option for service...  option name=networks service name=zabbix-web-nginx-mysql
WARN[0000] Skipping unsupported YAML option for service...  option name=networks service name=mysql-server
INFO[0001] Using ECS task definition                     TaskDefinition="ecscompose-zabbix-docker:40"
INFO[0002] Created an ECS service                        service=ecscompose-service-zabbix-docker taskDefinition="ecscompose-zabbix-docker:40"
INFO[0002] Updated ECS service successfully              desiredCount=1 serviceName=ecscompose-service-zabbix-docker
INFO[0003] Describe ECS Service status                   desiredCount=1 runningCount=0 serviceName=ecscompose-service-zabbix-docker
INFO[0018] ECS Service has reached a stable state        desiredCount=1 runningCount=1 serviceName=ecscompose-service-zabbix-docker

マネージメントコンソールでタスク定義をいじるようり、docker-composeの方がだいぶ楽ですね。

続きを読む

CRMのF-RevoをAWS Lightsailで構築したときにハマったこと(Apache,let’s encrypt)

はじめに

CRM(F-Revo)を導入したときにハマってしまったことを書いていきます。
F-Revoの環境についてはこちらです。
Lightsailどうこうではない部分もあります。

CRMをインストールしようとしたらページが真っ白になった件

F-Revoのインストール設定を入力したあと、こんなページまで行きます。

20150917093149.png

しかしこのあと次のページに遷移すると真っ白なページになって、戻るも進むなくなり、二進も三進もいかなくなりました。
原因はCRMがPHP7に対応していないからでした。
現場の開発はPHP7でやっていたため、できればPHP7を使用してF-Revoをインストールしたかったのですが、プライオリティは低いということでPHP5.6を再インストールしました。

参考
オープンソースなので、自己責任でソースを書き換えればPHP7でも動作するという書き込みもありましたのでご参考までに。
Vtiger with PHP7
https://discussions.vtiger.com/index.php?p=/discussion/183662/vtiger-with-php7/p1
PHP 7 compatibility
http://code.vtiger.com/vtiger/vtigercrm/issues/197

Let’s encryptがうまく実行されない件

オレオレ認証局ではなく、Let’s encryptを利用して証明書を作成しようと試みましたが失敗した話です。
結論から言うと、mod24_sslがインストールされていないからに落ち着きます。
「Let’s encryptはとにかく簡単。パッケージをインストールしてコマンドを叩けば自動で証明書の作成がされるよ」とみたいな話ではあるものの、凡ミスのせいで鮮やかにコケたというお話です。

ではコケるまでの手順を見ていきましょう。
1. インストールコマンドを叩く

$ wget https://dl.eff.org/certbot-auto
$ chmod a+x certbot-auto
$ ./certbot-auto --agree-tos --webroot-path <RootDirectory> -d <DomainName> -m <E-Mail>
※--webroot-pathはhttpdを実行したまま証明書を発行できるオプションです。

はい! ここでコケました!
そして下記のエラーが出力されました。

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for <DomainName>
No vhost exists with servername or alias of: <DomainName> (or it's in a file with multiple vhosts, which Certbot can't parse yet). No vhost was selected. Please specify ServerName or ServerAlias in the Apache config, or split vhosts into separate files.
Falling back to default vhost *:443...
Waiting for verification...
Cleaning up challenges
Failed authorization procedure. <DomainName> (tls-sni-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: Failed to connect to <IPaddress>:443 for TLS-SNI-01 challenge

IMPORTANT NOTES:

翻訳すると、「DomainNameを持つ仮想ホストは存在しません」みたいなことが書いてあり、「Apacheの設定でServerNameまたはServerAliasを指定するか、仮想ホストを別々のファイルに分割してください」ともあります。
試しにApache設定にVirtualHostを追記しましたがエラーに変化はないです。
/etc/resolv.confの設定ミスというわけでもなかったです。
443が云々というエラーメッセージもあるのでssl.confを見に行ってみると、ssl.confがないことに気づきました。
というわけで、mod24_sslをyum installし、Let’s encryptにて証明書発行が実行できました。

常時https接続に設定変更したらCRMのWEBページにたどり着けなくなった件

少し話が長くなりますので、結論からいうとconfig.inc.phpに記載されたsite_URLがhttp://~になっていたことと、/etc/httpd/conf.d/le-redirect-DomainName.com.confが原因でした。

事の始まり

Let’s encryptのコマンドを無事実行し、いよいよ終了が近づくと「httpもhttpsもイケるようにする?それとも常時https接続にする?」みたいな二択が表示されます。

・・・で、もともと常時https接続にする予定だったこともあり、常時の方を選択しました。
「よーしこれで80ポートは閉めていいな?」ということで、LightsailのGUIコンソール側でセキュリティルールを変更しました。
そしてこのあとユーザさんから「ログインできない!」と続々お問い合わせが来てしまったのです。
見てみると、エラー内容はタイムアウトでした。

となると、まず疑うべきは

  • 「常時https接続する」を選択したときに、自動でどこかにその設定を読み込むコンフィグが作成された可能性

ということです。そのコンフィグが作成されたこと一点が原因でログイン画面に行けないのであれば、コンフィグ名を変更してやることで今までのようにhttp接続でログインページにたどり着けるようになるはずです。

はい、ありました。le-redirectと名前がついてるので決定的です。
中身を見てみると、httpsにRewriteしているようです。とりあえずこのファイル名を変更し、httpdを再起動します。

/etc/httpd/conf.d/le-redirect-DomainName.com.conf
<VirtualHost _default_:80>
ServerName <DomainName>:443
ServerAlias <DomainName>
ServerSignature Off

RewriteEngine On
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]

ErrorLog /var/log/httpd/redirect.error.log
LogLevel warn
</VirtualHost>

ただ、これだけだと80ポートを閉じているのでhttp通信もできない状態。再度Lightsailの80ポートを開きます。
これで一旦、http通信ではあるけれどログインページにはこれまで通りいけるはず!

  • 強制リダイレクトしてるファイルを読み込ませない
  • http通信を許可する

応急処置が終わったら次はhttpsで接続できるようにしていきます。

そもそもなんでHTTPS接続できなかったか

いわゆるリダイレクトループと言えばいいんでしょうか。

リクエスト→http→強制でhttpsに変換→config.inc.phpに記載されたsite_URLがhttp://~のためhttpになる→強制でhttpsに→→→というイメージです。

config.inc.phpを一部抜粋するとこんな感じで記述されています。

/var/www/html/config.inc.php
$site_URL = 'http://<IPaddress>';

つまりこれを、httpsと記述してやればいいわけです。もっというと、ドメイン名でURLを表記させたいので以下のように変更しました。

/var/www/html/config.inc.php
#$site_URL = 'http://<IPaddress>/~';
$site_URL = 'https://<DomainName>/~';

そして改めて、必要のない80ポートを閉じます。
これで私の環境ではhttps接続が可能になりました!

おわりに

長くなりましたが、大抵ネットワーク関連で死ぬときは設定漏れか把握してないファイルがいるみたいなときなんですかね。ともあれユーザが安全、安定して使用してもらえるよう運用していきたいです。

続きを読む

ド素人がAWSでRuby on Railsを導入したメモ

はじめに

いい加減見るだけでなくなにかしら自分用にでもいいからアウトプットしてみようと思ったので書いてみました。
ほぼグラフィックデザイナーとしてしかやってこなかった自分が軽い気持ちで手を出しているので、そもそも理解できてない部分が多い上に無駄な工程、逆になぜそこを書かないんだ的なところもどっさりあるかと思います。
(一応、自分のWindows10PCに仮想環境あり、PHPとかjQueryとかMysqlとかほんの触り程度に知っているくらいですが超初級レベルです。)

参考にした記事とやったこと

導入できました!

その後、rubyは入ってるのに
$ ruby -v
が効かなくてrehashも結局試したけどだめだったので一度接続しなおしたらバージョンが表示されました。導入できたようです。ヤッタネ!

今後の課題とか所感

Railsをインストールするディレクトリ
何も考えずec2-user直下にインストールしたがこれで果たして良かったのか・・・
まだ何もいじっていないのでわからんですがちゃんと調べてから導入したほうがいいなと後から感じました。

開発環境に慣れる
これから仕事で使うことになるので否が応でも慣れるしかない・・・まずは何ができて何ができないのかを理解するところからですかね。

まとめるのって難しい!
今回こうして書いてみたら思っていた以上に書き起こすのが難しかったのと、Markdown方式できれいな記事に仕上げるのもなかなか至難の技だということがわかりました。
あとはいろんな人の記事をもっと読んで、また自分が書こうと思ったときに書いてぼちぼち慣れていければなと思います。

続きを読む

JenkinsおじさんのためのAWS Batch

はじめに

この記事の対象者

主にこんな感じの人をターゲットにしています。

  • Jenkinsでジョブを管理している
  • AWSをcliで触るのは実は大変…。GUIでやりたい
  • Dockerはインストールはしているけれど、あんまり触ったことが無い

また、本記事執筆時点では、us-east(virginia)でのみ利用可能なので、VPCでの利用はあまり想定していません。 (VPNを繋げば出来ると思いますが…)
本来はAuto ScalingやSPOTインスタンスと組み合わせたりといろいろあるのですが、私的事情により、志は低く、過疎っているJenkinsサーバを廃止(サーバレス化)することを目標にしています。

対象のJenkinsジョブ

今回ターゲットにするのは、Jenkinsだと一般的と思われる以下の処理とします。

  • JDKがバージョン指定で入っている
  • バッチ処理の入ったリポジトリをgit cloneしてくる
  • シェルスクリプトからごにょごにょして、リポジトリの中身を実行する

PHPやRubyなど別言語の人は、Javaな部分は脳内で別言語に置き換えてみてください。

AWS Batchでの流れ

Jenkinsでごく一般的なこの処理をAWS Batchでやろうとした場合、以下のような流れが一番シンプルになるかなと思います。

  1. JDK等、必要な実行環境を準備したDockerfileを作成する
  2. Jenkinsでやっていたシェル相当のシェルスクリプトを作成する
  3. リポジトリにDockerfileとシェルスクリプトを追加する
  4. Amazon ECRに設定を作成する
  5. Dockerfileでビルドし、JDK及びバッチ処理のリポジトリの入ったコンテナを作成し、ECRにプッシュする
  6. AWS Batchの設定(IAM Role, Compute Environment, Job Definition等)を作成する
  7. AWS Batchを実行する

というわけで、ハンズオン的に進めて行きたいと思います。

作業手順

1. Dockerfileの作成

古風なエンジニアにはこちらの記事が一番わかりやすいんじゃないかと思います。

効率的に安全な Dockerfile を作るには

今回のケースだとJavaのバッチ(Hello.class)を動かしたいので

$ ls
Hello.class

$ vim Dockerfile

として、以下のようなDockerfileを作成します。

Dockerfile
FROM centos:6

RUN yum install -y java-1.7.0-openjdk java-1.7.0-openjdk-devel
ENV JAVA_HOME /usr/lib/jvm/java-openjdk
RUN mkdir /opt/batch-directory
COPY . /opt/batch-directory/
WORKDIR /opt/batch-directory

Javaは諸々の事情からOpenJDKにしていますが、Oracle Javaが必要な場合は、少し手間はかかりますが、Oracle Javaでもコンテナを作成することはできます。また、本来だとベースイメージはAmazonLinuxだったりJavaが入ったコンテナの方が良いと思いますが、保守的な方のために、敢えてCentOSにしました。(あんまり意味ないかな…)

2. シェルスクリプトの作成

Jenkinsにバッチを実行するためのシェルスクリプト(Jenkinsでコマンド欄に入れていたようなもの)を作ります。

$ ls
Dockefile
Hello.class

$ vim batch.sh

今回は解説用なので雑なものを用意しています。

batch.sh
#!/bin/bash

java -version
java Hello

3. Dockerfileとシェルスクリプトをリポジトリに追加

せっかく作成したので、これらのファイルをGitリポジトリに追加しましょう。(これはこの後の工程上の必須項目ではないので、一連がテストされてからでも大丈夫です)

4. Amazon ECRにリポジトリを作成する

Amazon EC2 Container Registry(ECR)にリポジトリを作成します。ここではリポジトリ名を入れるだけです。
Amazon EC2 Container Service.png

5. Dockerfileでビルド

先ほど付けた名前を使って、Docker buildをします。

$ docker build -t unagi/jenkins-ojisan .

6. コンテナをECRに登録する

タグ付けして、先ほど作成したECRに登録してあげます。

$ aws ecr get-login --region us-east-1

# これでdocker loginに必要なコマンドがでてくるので、実際はそれを使う
$ docker login -u AWS -p xxxxxx -e none https://xxxx.dkr.ecr.us-east-1.amazonaws.com
$ docker tag unagi/jenkins-ojisan:latest xxxx.ecr.us-east-1.amazonaws.com/unagi/jenkins-ojisan:latest
$ docker push xxxx.ecr.us-east-1.amazonaws.com/unagi/jenkins-ojisan:latest

7. AWS Batchの設定をつくる

Job definitionとCompute environmentを設定します。

こちらがJob definitionで、コンテナを起動するときの設定になります。環境変数を設定できるので、パラメータを渡したい場合は使う事ができます。
AWS Batch (1).png

S3アクセス等でIAM Roleを使いたい場合は、ここで定義するJob Roleで定義する必要があります。そしてさらに分かりにくいことに、ここに表示されるIAM Roleを作るためには、信頼するエンティティがAmazon EC2 Container Service Task Role(ecs-tasks.amazonaws.com)のIAM Roleを作る必要があります。IAM Role作成時に似たようなのが沢山あるので、非常に解りづらいところです。

そして、次の画面はCompute environmentです。
AWS Batch (2).png
こちらはあまり見所は無く、淡々と設定していきます。ここで出てくるRoleは、ECSで動作するために必要なもので、コンテナで使うモノではありません。なので、適当に作成します…。

8. AWS Batchの実行

Job definitionsからSubmit jobして実行します。実行時に先ほど設定した環境変数を変更しながらの実行等もできます。
ちなみにこれも凄く分かりにくいのですが、Job definitionを編集したい場合はCreate new versionです。新しいバージョンの定義が出来てしまうので、古い方は不要になった段階で削除してしまいましょう。

9. 実行ログの確認

CloudWatchのログから見ます。Submitしてから起動までは少し時間がかかるので、少し待たないとログ出力はされません。

あとがき

Jenkinsおじさん的には、Dockerが出てくるため取っつき辛い印象を持つのかなと思います。
美しくDockerを使う場合はさておき、バッチ処理をやるだけであれば、Dockerfileに書くのはバッチサーバを作るときのセットアップコマンドで、一回やってしまえばあまり難しくないです。

続きを読む