🚀

[AWS] 日本語⇒韓国語に簡単翻訳するツールを、StreamlitとAmazon ECSで作成する

2022/05/30に公開約15,300字


はじめに

ご覧いただきありがとうございます。阿河です。

普段の業務でAWSを取り扱う中で、お客様から様々なサービス/構成の御相談を受けます。
私の担当はインフラ寄りではありますが、今後様々なニーズに答えられるようにスキルを身に着けていければと思っています。

この1週間ほど、Dockerについて学習しました。

Amazon Translate/PythonフレームワークであるStreamlitを使って簡単な翻訳ツールを作り、Amazon ECSでコンテナ化していきたいと思います。

対象者

  • AWSを運用中
  • コンテナサービスを触ってみたい
  • 普段アプリケーション開発には縁がないが、経験として触ってみたい

概要

(★)がついているセクションは、今回手を動かして頂く項目です。

  1. 今回のハンズオン構成
  2. 下準備(★)
  3. Amazon Translateで日本語⇒韓国語翻訳する(★)
  4. EC2にDockerをインストール/操作確認(★)
  5. Streamlitアプリケーション作成(★)
  6. Streamlitアプリケーションのコンテナ化(★)
  7. ECRへのアップロード(★)
  8. ECSの設定(★)
  9. 挙動確認(★)

各種公式ドキュメントを参照しながら進めていきます。

事前準備

  • AWSアカウント作成
  • AdministratorAccessを付与したIAMユーザーの作成

1.今回のハンズオン構成

【構成】

(2~5)

  • EC2
  • AmazonTranslate

(6~8)

  • Amazon ECS
  • Amazon ECR
  • AmazonTranslate

2.下準備

VPCまわりの下準備

  • VPC
  • Public Subnet(Internet Gatewayへのルート設定あり)/ Private Subnet

EC2の作成

・AMI: Amazon Linux2
・インスタンスタイプ: t2.micro
・Public Subnetに配置
・パブリックIP自動割り当て有効化
・セキュリティグループ(SSH/カスタムTCP=8000番ポートからのインバウンド通信許可)

上記設定でEC2インスタンスを作成します。
作成完了したら、SSH接続ができることを確認します。

Streamlitのインストール

  • EC2にSSHログイン

  • Pythonおよびパッケージ管理システムのインストール状況確認

$ sudo yum update -y
$ python3 --version
$ pip3 --version
  • Streamlitのインストール
$ pip3 install streamlit
$ pip3 list

Python でフロントエンド部分を構築出来るフレームワーク「Streamlit」をインストールします。

Amazon Translateの権限をもったIAMロールの作成および付与

IAMロールを作成します。
・信頼されたエンティティを選択では「AWSのサービス⇒EC2」を選択
・TranslateFullAccessの権限を追加(⇒Amazon Translate向け)
・AmazonEC2ContainerRegistryPowerUserの権限を追加(⇒Amazon ECR向け)

作成したロールをEC2に付与します。
EC2インスタンス画面のアクションから、ロール追加の設定に進めます。

3. Amazon Translateで日本語⇒韓国語翻訳する

Boto3のインストール

$ pip3 install boto3

翻訳用のpythonファイルを作成

$ mkdir test
$ cd test
$ vi translate.py

作業ディレクトリを作成し、testと名付けます。
pythonファイルを新規作成し、編集します。

コードはboto3のAPIリファレンスを参照します。
ブラウザで「boto3」と検索します。

boto3のページで、APIリファレンスに飛びます。
左側のサイドバーで、Amazon Translateを探します。

Translateのページでは、翻訳サービスを使うためにはどのようにコードを記述すればいいかが記述されています。

ではリファレンスを参考にして、コードを書いてみましょう。

translate.py
# boto3のインポート
import boto3

# 日本語から韓国語に変換するメソッドを定義
def get_ko_text(text):

    #クライアント
    trans_client = boto3.client('translate', region_name='us-east-1')
  
   #translate_text
    res = trans_client.translate_text(
        Text=text,
        SourceLanguageCode='ja',
        TargetLanguageCode='ko'
    )
    return res

ここでやりたいことは3つです。

・boto3のインポート
・クライアントの作成
・translate_text

translate_textは、入力テキストをソース言語からターゲット言語に変換します。

パラメータのTextは翻訳対象のテキストであり、引数で渡されたtextを格納します。
ソース言語とターゲット言語には日本語と韓国語を指定します。
各言語の記述方法はこちらが参考になると思います。

translate_textの結果をresに格納し、戻り値として返します。
これにより「引数として渡された日本語のtextを、韓国語に変換して返す」翻訳機能を作成できました。

次にtranslate.pyテスト用のファイルを作成しましょう。

test.py

import translate
ja_text= 'こんにちは'
text = translate.get_ko_text(ja_text)
print(text)

「こんにちは」という日本語を、translate.pyのget_ko_textメソッドに渡します。
メソッドは日本語を韓国語に翻訳して、test.pyに渡します。

ではtest.pyを実行してみましょう。

$ python3 test.py

大量の値が返ってきました。

リファレンスによると、translate.textの戻り値はdict型で返されます。

その中でTranslated_Text(文字列)が翻訳されたテキストにあたるので、コードを一部変更して、返す値を制限します。

translate.py

return res.get('TranslatedText')

TranslatedTextの値のみ返すようにします。
結果は変わるでしょうか。

再びtest.pyを実行すると、韓国語で「こんにちは」(안녕하세요)が返ってきました。

このようにAmazon Translateを活用すれば、簡単に翻訳処理ができます。
この記事を書いている段階では、75種類の言語間翻訳に対応しているようです。

4. EC2にDockerをインストール/操作確認

このセクションではEC2にDockerをインストールして、基本操作の中でコンテナ作成の流れをつかみます。

Dockerのインストール
$ sudo yum install -y docker

Dockerについて

インストールが完了したら、Dockerの概要について調べてみます。

Dockerドキュメントを参照します。

イメージの元となるDockerfileの作成⇒Dockerfileからイメージをビルド⇒イメージを基にコンテナを起動します。

イメージとは、Dockerコンテナを作成する命令が入った読み込み専用のテンプレート。通常イメージは、他のイメージ(CentOSやUbuntuなど)をベースにして、そこにApacheなど必要なものをカスタマイズして利用します。

イメージを自分で作る場合は、Dockerfile(イメージを生成して実行するまでの手順を定義)というファイルを生成します。

コンテナとは、イメージが実行状態となったインスタンスを指します。サーバ上に隔離されたアプリ空間を作ります。

では実際に操作してみましょう。

Dockerfileを作成

新規フォルダ(docer_test)を作成。配下に新規ファイル(Dockerfile)を作成

$ mkdir docker_test
$ vi docker_test/Dockerfile
Dockerfile
FROM nginx

Dockerfileはテキストファイルであり、イメージを作り上げるために実行するコマンドライン命令を全てこのファイルに含められます。

FROMでベースイメージの指定を行います。
このDockerfileをもとにビルドを行うことで、nginxをベースとしたイメージを作成します。

Dockerfileをビルドして、Dockerイメージを作成(docker build)

# ec2-userにdockerの実行権限を与えた後、ログインし直す
$ sudo usermod -a -G docker ec2-user
$ exit

$ docker build -t test:latest docker_test

ec2-userでコマンドを実行している場合、buildコマンド時にエラーが発生するはずです。
Dockerをroot以外のユーザーとして管理できるようにします。
こちらを参照ください。

docker buildを実行すると、Dockerfile からイメージを構築します。

イメージの確認

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    de2543b9436b   9 days ago     142MB
test         latest    de2543b9436b   9 days ago     142MB

docker imagesで、イメージを一覧表示できます。
結果としてnginxのイメージと、それをベースとしたtestイメージが作成されているのが分かります。

イメージを利用して、コンテナを作成(docker run)

$ docker run --name testcon -d -p 80:80 test:latest

docker runで、testconという名前のコンテナを作成します。
元となるイメージには、先ほど作成したイメージの名前を指定します。

試しにお手持ちのブラウザで、EC2のIPアドレス宛てにアクセスしてみましょう。

Nginxのテストページが表示されました。

コンテナとイメージの削除

$ docker stop testcon
$ docker rm testcon

$ docker rmi test

最後にコンテナの削除と、イメージの削除を行います。

以上がコンテナの作成/削除の流れです。他の操作は必要に応じて補足していきます。

では次のセクションで今回のテーマに沿って環境を作成してみます。

5. Streamlitアプリケーション作成

フロントエンド側を作成

ではStreamlitでフロントエンド側を作成する。
testディレクトリの配下に、新規ファイル(app.py)を作成。

app.py
# streamlitをインポート
import streamlit as st

# 入力フォームを表示
# 入力フォームには文字を入力できる
st.header("Translate from Japanese to Korean")
txt = st.text_area("Please enter Japanese",height=300)

# 翻訳ボタン
button = st.button("Translate")

# 翻訳ボタンを押すと、下部に出力フォームが現れます
if button:

    # 入力フォームに入れた文字が出力フォーム内に表示される 
    st.text_area("machine translation",txt,height=300)

Streamlitには、フロントエンドを作成するために便利なツールがたくさんあります。
公式のAPIリファレンスで、必要な部品を探します。

今回は
・ヘッダーとしてst.header
・入力フォームとしてst.text_area
・ボタンとしてst.button
を使用します。

app.pyを保存したら、app.pyを実行します。

$ streamlit run app.py

app.pyを実行すると、ターミナルにアクセスするためのURLが表示されます。
http://[※EC2のIPアドレス]:[※ポート番号]

ポート番号を確認して、EC2のセキュリティグループのインバウンド通信(上記のポート番号からの)を許可します。

インバウンド通信を許可したら、ブラウザでURLにアクセスします。

シンプルな入力フォームができました。

入力フォームに適当に文字を入れます。
翻訳ボタンを押すと、下部に出力フォームが現れます。

先程入力フォームに入れた文字が、出力フォームにも表示されます

翻訳機能を追加する

入力フォームに入れた文字を、韓国語に翻訳して出力を行います。

翻訳機能は既にtranslate.py(同じtestディレクトリ内にある)に実装しています。
app.pyを編集します。

app.py

import streamlit as st
import translate # translateをインポート

st.header("Translate from Japanese to Korean")
txt = st.text_area("Please enter Japanese",height=300)

button = st.button("Translate")

if button:
  # translate.pyに定義した翻訳メソッドにtxtを渡す
    trans_txt = translate.get_ko_text(txt)
    
    # 翻訳したtrans_textを出力フォームに表示
    st.text_area("machine translation",trans_txt, height=300)

日本語から韓国語に翻訳されました。
これで簡易的な翻訳ツールができました。

次のセクションでコンテナ化をしていきます。

6. Streamlitアプリケーションのコンテナ化

コンテナ用のディレクトリを作成し、Dockerfileを作成します。

$ mkdir trans
$ vi trans/Dockerfile

Dockerfileを新規作成します。

Dockerfile

FROM python:3.7.10
RUN pip3 install streamlit
RUN pip3 install boto3
RUN mkdir /trans
COPY app.py /trans/
COPY translate.py /trans/
ENTRYPOINT ["streamlit"]
CMD ["run", "trans/app.py"]
EXPOSE 8501

ベースイメージとして、python3.7.10を使用。

また今回testディレクトリで作成していたapp.pyとtranslate.pyを流用するので、それぞれのpythonファイルに必要な機能をインポートします。

translate.py

import boto3

def get_ko_text(text):

    trans_client = boto3.client('translate', region_name='us-east-1')

    res = trans_client.translate_text(
        Text=text,
        SourceLanguageCode='ja',
        TargetLanguageCode='ko'
    )

    return res.get('TranslatedText')

app.py

import streamlit as st
import translate

st.header("Translate from Japanese to Korean")
txt = st.text_area("Please enter Japanese",height=300)

button = st.button("Translate")

if button:
    trans_txt = translate.get_ko_text(txt)
    st.text_area("machine translation",trans_txt, height=300)

translate.pyにインポートするboto3、app.pyにインポートするstreamlitをそれぞれインストールします。

Dockerfileの中身の説明に戻ります。
コンテナ内部にtransディレクトリを作成し、COPYでその配下にapp.pyとtranslate.pyをコピーするようにします。

それぞれのDockerコマンドの使い方は、リファレンスを参照ください。

Dockerfile以外に必要なファイルを用意します。

$ cp test/app.py trans/
$ cp test/translate.py trans/

$ ls trans
app.py  Dockerfile  translate.py

testディレクトリに作成した2つのファイルを、transディレクトリ配下にコピーします。
transディレクトリ配下にDockerfileと2つのファイルが存在している状態です。

必要なファイルが用意できたので、イメージ⇒コンテナを作成します。

$ docker build -t ko_translate_im trans
$ docker run --name ko_translate_app -d -p 8506:8501 ko_translate_image 
$ docker ps

docker psで、コンテナが実行されていることを確認します。
EC2のセキュリティグループで、8506番ポートのインバウンド通信を許可しておきます。

ブラウザでURLにアクセスしてみます。

http://[※EC2のアドレス]:8506/

無事コンテナ化までできました。

コンテナは停止しておきます。

docker stop ko_trans_app

7. ECRへのアップロード

AWSのマネジメントコンソールに移動して、ECSのページに飛びます。

左のサイドバーから、ECRリポジトリを選択。

プライベートリポジトリを選択して、リポジトリを作成に進みます。

適当なリポジトリ名をつけて、作成を行います。

リポジトリとそのURIが発行されました。
右上のプッシュコマンドを選択します。

ECRへのプッシュのやり方(コマンド)がのっていますので、4つの手順に従ってください。

レジストリに対して、Dockerクライアントの認証を実行します。

$ docker tag ko_translate_ecs:latest xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ko_translate_ecs:latest

今回はEC2からECRへプッシュするので、コマンドが失敗する場合はロールで正しい権限が付与されているかを御確認ください。

イメージは既に構築されているので、2の手順は飛ばします。

リポジトリにイメージをプッシュできるように、イメージにタグづけします。

$ docker tag ko_trans_image:latest xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ko_translate_ecs:latest

最後にリポジトリにイメージをプッシュします。

$ docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ko_translate_ecs:latest

AWSマネジメントコンソールのECRページに戻ると、イメージがアップされていることが分かります。

ECRにイメージをプッシュできたので、次のセクションでECSの設定を行っていきます。
ECSのタスク定義の際に、上記のイメージURIを使用するので、メモしておきます。

8. ECSの設定

ECRにイメージをプッシュしたら、次はECSクラスタの作成とタスク定義を行います。

ロールを作成

AmazonEC2TaskExecutionRolePolicyを選択します。

ecsTaskExecutionRoleと名付けて、ロールの作成を行います。

ECSクラスタの作成

ECSのページでクラスターの作成を選択。

「EC2 Linux + ネットワーキング」を選択します。

次の画面ではクラスターの設定を行います。

t2.microのオンデマンドインスタンスを利用することにします。
画像には映してないですが、EC2インスタンス内にSSHログインできるようにキーペアを選んでおいてください。

サブネットはパブリックサブネット。
パブリックIPの自動割り当ては有効。

セキュリティグループは、ブログの前半で利用していたEC2のセキュリティグループと同じ設定にします。

ロールは自動で生成されます。

作成に進むと、クラスターが作成されます。

タスク定義

ECSのページで、新しいタスク定義の作成を選択します。

今回はEC2を選択します。

先程作成したecsTaskExecutionRoleをロールに設定します。
ネットワークはdefaultを選択。

タスクサイズについて。Amazon EC2 インスタンスでホストされるタスクの場合、これらのフィールドは省略可能とあるので、省略します。

コンテナの追加をクリックします。

イメージには、ECRに作成したリポジトリのURIをコピーして貼り付けてください。

ポートマッピングはDockerで設定していた8506:8501をそれぞれ入力します。
あとはデフォルトのまま確定します。

コンテナが追加されています。

サービス統合以降もデフォルトのままで進めます。
作成ボタンをクリック。

ECSにコンテナをデプロイ

クラスターを選択⇒タスクタブから「新しいタスクの実行」を選択。

先程作成したタスク定義を選択。

今回コンテナ1つだけ起動させるので、タスクの数は1にする。

その他はデフォルトで進めます。

ステータスがRUNNINGになっています。
なおEC2のリンクに飛んで、セキュリティグループで所定のポートのインバウンド通信が許可されているかを確認してください。

三角マークを押すと、外部リンクが載っています。

9. 挙動確認

外部リンクに飛んでみましょう。

Streamlitのページが表示されました。
翻訳してみましょう。

エラーが起きます。
アクセスが拒否されています。

原因として考えられるのは翻訳機能を提供するAmazon Translateの権限がないことです。

タスクロールに、Amazon Translateの権限を追加します。
もう一度外部リンクに飛んでみましょう。

無事翻訳されました。

さいごに

以上 簡単な翻訳ツールをコンテナ化してみました。
お疲れ様でした!!

Discussion

ログインするとコメントできます