Windows 10 にDockerをいれてPythonを実行して、その勢いでCloudFormation一発でECS上でも実行してみた
梶原大使(ambasad)です。
Windows 10 上にUbuntu18.04をインストールしPython3を実行するまでを公開したところ、Dockerが便利ですよ!というコメントを頂いたのでさっそく、弊社お作法にのっとりブログでお返事したいと思います。
今回、Docker, AWS CLI, CloudFormationなど各コマンドにの詳細については割愛させていただいてます。
Docker を触ったことがない方、またAWS ECSの敷居を下げることができたら幸いです。
では、サクサク行きます。
Docker for Windows でやってみる
環境
- OS: Windows10 Pro
- Hyper-vに対応したCPU、また有効化が必要になります
- 要ブロードバンド
Hyper-Vの有効化
管理者権限でPowerShellを起動します
PS C:\WINDOWS\system32> Get-WindowsOptionalFeature –Online -FeatureName Microsoft-Hyper-V-Hypervisor FeatureName : Microsoft-Hyper-V-Hypervisor DisplayName : Hyper-V Hypervisor Description : Hyper-V Hypervisor を提供します。 RestartRequired : Possible State : Disable CustomProperties :
無効になっていた場合は、有効にしてください
PS C:\WINDOWS\system32> Enable-WindowsOptionalFeature –Online -FeatureName Microsoft-Hyper-V-Hypervisor
Docker Community Edition for Windowsのインストール
Docker Community Edition for Windows のインストールを行います。
下記URLから
https://store.docker.com/editions/community/docker-ce-desktop-windows
※Docker IDを持たれていない場合は登録が必要になります
[Please Login to Docker]
を押下して、Docker IDの登録またログインを実施してください
から、[Get Docker!]を押下
ダウンロードした
Docker for Windows Installer.exe
を実行してインストール行います。
必要に応じて、再起動を実施して、インストールを完了してください。
インストール確認
Docker が起動すると、タスクバーにクジラのアイコンが見えると思います。
さてコマンドプロンプト or PowerShell より
PS > docker --version Docker version 18.03.1-ce, build 9ee9f40
何はともあれ Hello World
PS > docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world ~ 中略 ~ Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly.
correctly. の文字が嬉しいですね。
DockerでPyton3.6の環境構築
早速、目的のDocker上でPython 3.6の環境が欲しいのですが 公式のイメージがありますのでそちらを取得して使います。 pull コマンドを使って取得します
PS > docker pull python:3.6 3.6: Pulling from library/python cc1a78bfd46b: Pull complete ~ 中略 ~ Status: Downloaded newer image for python:3.6
早速Dockerで取得したPython3.6のイメージを起動します 今度は run です。
PS > docker run --name python36 -i -t python:3.6 /bin/bash root@34cead30fd93:/# python --version Python 3.6.5 root@34cead30fd93:/# exit
初回はダウンロード時間が若干かかるものの、あっという間のうちに入るのではないでしょうか また、Dockerでイメージでの利用ができる為、環境の再利用なども手軽にできます。
ついでと言って何ですが、Python 2.7 環境も同じようにしてみます。
今回はpullせずに実行してます、イメージがない場合取得して実行してくれます。(すでにあるものはスキップして必要なものだけ取得します)
PS > docker run -it python:2.7 /bin/bash Unable to find image 'python:2.7' locally 2.7: Pulling from library/python cc1a78bfd46b: Already exists <= (これはすでにあるからスキップ) ~ 中略 ~ Status: Downloaded newer image for python:2.7 root@c6b156d6d697:/# python --version Python 2.7.15 root@c6b156d6d697:/# exit
おお。
Docker すばら。
さて、これだけですと、AWSの話がでてこなくて、BOSSがやってきそうなので
この勢いでAWS上のAmazon Elastic Container Service (Amazon ECS) で同じように実行してみます。
ECSでやってみる
本項内容を実際に実行する場合は
AWS アカウントとアクセスキーとシークレットキーが必要になるので
こちらの記事などを参考に取得しておいてください。
(※実際にアクセスキー、シークレットキーを多用する場合はgit-secretsなどの使用もご検討ください)
また課金が発生しますので、各コマンドについてご理解、ご注意の上実行ください。
ざっくりいうと、t2.microのインスタンスが立ち上がります。
また、秘密鍵で制限されているとはいえ、SSHポートがオープン状態となりますので
ご注意ください。
また、手順の最後に課金対象のインスタンスは消すようにしますが 改めて消し忘れ等がないかAWSコンソールなどでご確認ください。
では、早速。
AWS環境初期設定
さて、丁度いいところに、Python 3.6の実行環境があるので AWS CLI をインストールします
PS > docker start python36 PS > docker attach python36 root@34cead30fd93:/# pip install awscli --upgrade --user root@34cead30fd93:/# echo 'export PATH=~/.local/bin:$PATH' >> ~/.bashrc root@34cead30fd93:/# source ~/.bashrc root@34cead30fd93:/# aws --version aws-cli/1.15.40 Python/3.6.5 Linux/4.9.87-linuxkit-aufs botocore/1.10.40 root@34cead30fd93:/# exit PS > docker commit python36 my_awscli
AWS CLIの認証設定
AWS CLIの認証設定を実施します。
尚、ここからローカルのCドライブ上のdataディレクトリを
コンテナと共有していきます。(ディレクトリは任意です)
また、先ほどこそっと最後に commit した "my_awscli" のコンテナイメージを使用して新しくコンテナを起動します。
自分で作ったawscliのイメージが使いまわせるって、Dockerいいですね。
コンテナを起動し、アクセスキーとシークレットキーを設定します。
PS > docker run -it -v C:\\data:/root/data my_awscli /bin/bash root@df2f35df4933:/# aws configure AWS Access Key ID [None]: HOGEHOGE <== ここ AWS Secret Access Key [None]: FUGAFUGA <== ここ Default region name [None]:ap-northeast-1 Default output format [None]:(Enter) (疎通確認) root@df2f35df4933:~# aws s3 ls
認証設定がうまくいっていれば、S3バケットのリストが出るはずです(バケットがない場合はエラーがでないことをご確認ください)
ECS クラスタ環境構築
後程コンテナインスタンスへログインを実施するのでキーペアを作成します。 キーの名前は[ecs]としています。すでにあるキーを使用される場合は後でパラメータで指定します。
# cd # aws ec2 create-key-pair --key-name ecs --query 'KeyMaterial' --output text > /root/data/ecs.pem # cp /root/data/ecs.pem ~/ecs.pem # chmod 400 ~/ecs.pem
さてここからは、DOP認定の試験勉強を兼ねてAWS Cloud Formationを使って、一発でECSのインスタンスを作ります。 尚、こちらのCloud Formationスタックは、ECSの初回実行ウィザードを元にして、変更を加えています。
EC2用のRole, Profile, VPC,Subnet,Internet Gateway, AutoScaleGroup,ECSクラスタなどを作成し、最終的にはEC2ベースのECS環境ができあがります。
Cloud Formation テンプレートの取得
ファイルはGitHub上に置いてますので、インスタンス上から取得するか githubから取得してコンテナと共有しているディレクトリ(ここでは:C:\data)に保存してください。
CloudFormationテンプレート本体: EC2ContainerService.json
CloudFormationパラメータ: EC2ContainerService-param.json
# cd /root/data/ # wget https://raw.githubusercontent.com/ambasad/devio-blog-cfn/master/ecs/EC2ContainerService.json # wget https://raw.githubusercontent.com/ambasad/devio-blog-cfn/master/ecs/EC2ContainerService-param.json
CloudFormation テンプレートのチェック
# aws cloudformation validate-template --template-body file://EC2ContainerService.json
一応執筆時点で(2018/06/23)動くことは確認していますが、もしエラーがでたらご容赦ください。 また、SSHポートをオープンしますので、必要に応じてEC2ContainerService-param.jsonを編集し 接続元のIPアドレス制限を実施ください。
パラメータファイル(EC2ContainerService-param.json)の[SourceCidr]になります。
小ネタ。自分のIPアドレス取得
# curl -s https://checkip.amazonaws.com/ # xxx.xxx.xxx.xxx
EC2ContainerService-param.json の下記部分を修正ください
{ "ParameterValue": "xxx.xxx.xxx.xxx", <= 取得した自IPに変更してください "ParameterKey": "SourceCidr" }
あとは、うまく動くことを願ってCloudFormationの実行をします。
# aws cloudformation create-stack --stack-name EC2ContainerService-python \ --template-body file://EC2ContainerService.json \ --parameters file://EC2ContainerService-param.json --capabilities CAPABILITY_IAM
状況確認
# aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE { "StackSummaries": [ { "StackId": "arn:aws:cloudformation:ap-northeast-1:NNNNNNNNNNNN:stack/EC2ContainerService-python/XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX", "StackName": "EC2ContainerService-python", "TemplateDescription": "AWS CloudFormation template to create a new ECS First Run stack", "CreationTime": "2018-06-23T03:10:16.274Z", "StackStatus": "CREATE_COMPLETE" },
構築正常が終了していれば、画面上に表示されると思われます。
(AWS CloudFormationのコンソールなどでも確認できるかと思います)
続いて、ECS起動用のインスタンスができたのでECSのタスク定義を行います。
タスク定義
Python 2.7用のタスク定義(パラメータで定義)
# aws ecs register-task-definition --family python27 --container-definitions "[{\"name\":\"python27\",\"image\":\"python:2.7\",\"command\":[\"tail\",\"-f\",\"/dev/null\"],\"memory\":32}]"
Python 3.6用のタスク定義(jsonファイルで定義)
個人的にはこちらの方が見やすいので好きです。
# cat << EOT > python36.json { "containerDefinitions": [ { "name": "python36", "image": "python:3.6", "command": [ "tail", "-f", "/dev/null" ], "memory": 32 } ], "family": "python36" } EOT # aws ecs register-task-definition --cli-input-json file://./python36.json
上記タスク定義を公開されている他のコンテナなどで置き換えれば さまざまなコンテナを起動することができます。 また、自分で作成したコンテナイメージ等も使用できますので 次回ECRを使用した作成方法なども検討したいと思います。
タスク一覧
# aws ecs list-task-definitions
タスク実行
# aws ecs run-task --cluster python --task-definition python27 --count 1 # aws ecs run-task --cluster python --task-definition python36 --count 1
上記のcountを2などにすると、自動で2つコンテナが起動されます。 挙動を見たい方はいろいろと変更してみてください。
EC2への接続
先ほどCloudFormationで起動したECSのコンテナインスタンスのホスト名を取得します。 タグ名で検索かけます。
# aws ec2 describe-instances --filters "Name=tag:Name,Values=ECS Instance - EC2ContainerService-python" --query Reservations[].Instances[].PublicDnsName [ "ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com" ]
出力されたホスト名がECSのインスタンスになります。
Pythonの実行
早速ですが、EC2に接続してPythonを実行してみます。
ssh -i ~/ecm.pem ec2-user@ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com [ec2-user@ip-xxx-xxx-xxx-xxx ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7a995118a762 python:2.7 "tail -f /dev/null" 9 minutes ago Up 9 minutes ecs-python27-2-python27-c4c8aee9cbeff2b54800 2038b3d784f4 python:3.6 "tail -f /dev/null" 9 minutes ago Up 9 minutes ecs-python36-10-python36-ecf4aacc9b93dc844400 bc2bb882aab9 amazon/amazon-ecs-agent:latest "/agent" 25 minutes ago Up 25 minutes ecs-agent [ec2-user@ip-xxx-xxx-xxx-xxx ~]$ docker exec -it 7a995118a762 /bin/bash root@7a995118a762:/# python --version Python 2.7.15 root@7a995118a762:/# exit [ec2-user@ip-xxx-xxx-xxx-xxx ~]$ docker exec -it 2038b3d784f4 /bin/bash root@2038b3d784f4:/# python --version Python 3.6.5 root@2038b3d784f4:/# exit
作成したECSインスタンスが1つしかないため、すべてのおなじインスタンス上にある状態 となります。AutoScaleのインスタンスのパラメータを2に変更すると複数EC2インスタンが起動され分散されます。 AWSのコンソールなどから、いろいろとパラメータを変更したりして、挙動を確認するとなかなか面白いのではないでしょうか。
後片付け
では、課金されてしますので、さくさくと消していきます。
作成したECS環境を削除
aws cloudformation delete-stack --stack-name EC2ContainerService-python
ただここで、作成したAWS環境が消えるはずですが、執筆時点ではクラスタの削除がうまくいきません。(時間をおいて何度かリトライすると消えます) ここまできて、若干負けた気がしますが、AWSコンソールから作成したクラスタを削除した方が正常に終了しますのでそちらもご案内します。
AWS コンソールから削除
AWS コンソールからAmazon ECSのコンソールへ移動し 今回CloudFormationから作成したPythonのクラスタを選択します。
選択したクラスタのページより、「クラスタの削除」をクリックします。
削除確認のポップアップが表示されますので、押下し数分待ちますと削除されます。
まとめ
さて、pythonの環境が欲しいだけの理由であまりこういった使い方はしないのですが ECSを使ってみる垣根が少しは下がれば幸いです。 dockerやAWS CLI等のコマンドの説明をしていませんが各コマンドを調べてみてみるのも勉強になるかと思います。 次回はAWS ECRを使用したCloudFormation一撃作成などもやっていきたいと思います。