- 投稿日:2019-07-10T23:57:46+09:00
socat でコンテナ内のコマンドを TCP ソケット経由で実行する
標準入出力を利用するコマンドを外部からネットワーク経由で実行したいことありませんか?
コンテナを使っているとまれにありますよね。例えばデータサイエンティストが実装したシンプルな Python スクリプトとか。
socat
を使って TCP ソケット経由で外部からコマンドを実行できるようにしてみました。課題
例えば 1マイクロ秒の誤差もないすごい
date
コマンドを持っているコンテナがあるとします。このコンテナはdocker run date:latest
を実行すると日時を標準出力に表示します。
このdate
コマンドをホスト側から実行するのは容易ですが、別のコンテナから実行したくても直接コマンドを実行する方法が見つかりませんでした。これを実現するために ssh や Docker on Docker で
date
コンテナを実行する方法もありますが、呼出元のコンテナに Docker をインストールしたりdocker.sock
を共有したり事前準備がやや面倒です。この記事では上記のような「別コンテナのコマンドを実行して標準出力を取得したい」ケースを
socat
を使って解決します。具体的な例
前の記事でヘッドレス Chrome を使用して HTML を標準出力にダンプするコンテナを作成しました。このコンテナを実行すると対象のウェブサイトの HTML が出力されます。
$ docker pull grohiro/headless-chrome $ docker run grohiro/headless-chrome http://www.google.com/ #=> (HTMLが出力される)コンテナの内部では
gooogle-chrome
コマンドを実行して HTML をダンプしています。このコンテナをsocat
を使って TCP ポート 9000 経由で外部から実行できるようにします。コンテナイメージの作成
まずは上記の Chrome コンテナに
socat
を追加したイメージを作成します。そしてヘッドレス Chrome を起動するラッパースクリプトも追加します。Dockerfile
FROM grohiro/headless-chrome USER root RUN apt-get install -y -qq socat COPY ./chrome.sh / ENTRYPOINT ["socat", "tcp4-listen:9000,fork,reuseaddr", "system:/chrome.sh"]chrome.sh
#!/bin/sh read URL google-chrome --headless --no-sandbox --dump-dom --start-maximized --disable-gpu "$URL"ファイルを作成したら Docker イメージをビルドします。名称は
headless-chrome-socat
です。$ docker build -t headless-chrome-socat .作成したコンテナを実行すると TCP ポート 9000 が
socat
にバインドされて LISTEN 状態になります。このポートに送信したデータはchrome.sh
の標準入力に渡されます。
chrome.sh
は標準入力の文字列を Chrome の引数として実行します。Chrome は指定された URL を読み込み HTML を標準出力にダンプします。
socat
はこの標準出力をリクエスト元のコンテナにレスポンスとして返します。実行元のコンテナはソケットの入力を読み込むことで Chrome がダンプした HTML を取得することができます。
動作確認
まずはホスト側から手動で URL を入力して HTML が出力されるか確認します。
以下のコマンドで作成したコンテナのポート 9000 を
127.0.0.1:9000
にマッピングして起動します。$ docker run -p 9000:9000 headless-chrome-socatポート 9000 に接続して URL を送信してみましょう。
$ nc 127.0.0.1 9000 http://www.google.com #=> (HTMLが出力される)入力した http://www.google.com が
chrome.sh
経由でヘッドレス Chrome に渡されて HTML が出力されました。docker-compose
ここまでできたら
docker-compose.yml
を定義します。docker-compose.yml
services: crawler: # コマンド実行元のコンテナ image: php:7.5-slim chrome: # ヘッドレス Chrome コンテナ image: headless-chrome-socatこの
docker-compose.yml
でcrawler
コンテナの中からtcp://chrome:9000
に URL を送信すると Chrome が実行されて HTML が取得できるようになりました。例えば
crawler
コンテナ内の PHP からはfsockopen()
を使ってデータを読み書きできます。$response = ""; $fp = fsockopen('chrome', '9000'); if ($fp) { fwrite($fp, "https://www.google.com\n"); while (!@feof($fp)) { $response .= fgets($fp, 4096); } }
- 投稿日:2019-07-10T23:04:54+09:00
Redmineのローカル環境をDockerで簡単に構築する
Docker for Macをインストール
Docker for Macのダウンロードページからdmgをダウンロードします。
※Docker IDを作る必要があります。
ドラッグ&ドロップでmacにインストールします。
アプリケーションをダブルクリックで起動して画像のようなウインドウが出ればOKです。
メニューバーにくじらのアイコンが出て、画像のように緑色の丸と一緒に「Docker Desktop is Running」と出ていればDockerが起動しています。
RedmineをDocker経由で持ってくる
Docker Hubのredmine公式イメージからコマンドをコピーし、CUIで実行
コピーしたコマンドを実行します
$ docker pull redmine
下記のようになればOKです。
Using default tag: latest latest: Pulling from library/redmine fc7181108d40: Pull complete d5e459c0e2e8: Pull complete 9d72610672ed: Pull complete 8021817cc2b5: Pull complete 11df209a1902: Pull complete 22d9ea80dda2: Pull complete 44657032d49c: Pull complete 52667b1ef3e5: Pull complete ecbc5377aa1e: Pull complete 91c3a7d560ed: Pull complete 7023fe92c4a0: Pull complete 4b79f7046904: Pull complete 443f0769b46f: Pull complete Digest: sha256:bbf8fa56934342c33e415ead52a75ca9e052818bd1bead59b0395c67e1fed626 Status: Downloaded newer image for redmine:latestRedmineのローカル環境構築
redmineのDockerイメージがあるか、「docker images」で確認します。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE redmine latest 3f1c9319f54c 6 days ago 579MB
Dockerイメージを確認できたら、「docker run」でコンテナを立ち上げます。
$ docker run -d --name redmine -p 8080:3000 redmine
- -d(--detach):バックグラウンドで起動する
- -p:ポートフォワード ローカルのポート : Dockerコンテナのポートで指定する
http://localhost:8080/にアクセスするとredmineのローカル環境が構築されています。
- 投稿日:2019-07-10T22:53:18+09:00
RailsチュートリアルのためにDockerコンテナの作成 for Windows
動機
これからRailsチュートリアルを始めることにしました。しかしながら、自宅デスクトップPCでもモバイルノートPCでも進めたいと思うのです。自宅メインPCは環境構築が面倒なことで有名なWindows。一方でモバイルノートPCのMacOSの環境も汚したくない。環境依存の問題が出るのは困る。というわけで、開発環境は仮想化します。
Docker for Windowsのインストール
私の場合は、Chocolatey経由でDocker for Windowsをインストールしました。Chocolateyを使ったアプリケーションのインストールを行う場合、Powershellに管理者権限が必要となります。
powershell$ choco install docker-desktopDocker for Windowsがインストールされているか確認
Windows Powershellで以下のコマンドを実行します。管理者権限は必要ありません。
powershell$ docker -vDocker for Windowsが正しくインストールされていれば、実行結果は以下のようになります。
powershellDocker version 18.09.2, build 6247962バージョンが表示されていますね。
Railsチュートリアル用のコンテナ作成
Dockerイメージの入手 - Ruby 2.5.1
Dockerコンテナを作成するために、Dockerイメージを入手しなければなりません。
Dockerイメージという言葉そのものがわからない初心者なので、Google検索をかけてみます。すると、Dockerイメージとは以下のようなものであると言及されていました。
- コンテナの土台 - イメージの構築 - Docker-docs-ja 1.9.0b ドキュメント
- Dockerコンテナを作成する際に必要となるファイルシステム - Dockerイメージとは?【Docker解説】 - tataneのうたたね
- コンテナを作成するためのファイルシステムや設定をまとめたもの - さわって理解するDocker入門 第1回 Dockerのイメージ・コンテナ管理の仕組み - オブジェクトの広場
Dockerコンテナを作成する以前の段階で必要になる、ということですね。
Windowsにおけるコンテナイメージの入手は、Windows Powershellで
docker pull
コマンドを実行することにより行います。管理者権限は必要ありません。ネットワークエラーの発生と解決
powershell$ docker pull ruby:2.5.1 Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)Docker DesktopのSettingsウィンドウを開き、Network - DNS Serverの設定値を
Automatic
からFixed:8.8.8.8
に変更することにより解決しました。なお、DNSサーバーの設定を変更すると、その時点でDocker Desktopの再起動がかかります。再起動の完了を示すバルーンが表示されるまできちんと待ちましょう。
powershell$ docker pull ruby:2.5.1 error during connect: Post http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.39/images/create?fromImage=ruby&tag=2.5.1: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.上記のエラーは、Docker Desktopの再起動が終わっていないのに
docker pull
しようとした場合に発生するエラーです。今度こそ
docker pull
Dockerによる仮想環境の構築といっても、まず仮想環境のイメージを入手しないと話になりません。
docker pull
は、Docker Hubで用意されているイメージを入手するためのコマンドです。powershell$ docker pull ruby:2.5.1
Rubyのバージョンは、2.5.1決め打ちとします。
powershell$ docker pull ruby:2.5.1 2.5.1: Pulling from library/ruby ...省略 Status: Downloaded newer image for ruby:2.5.1今度こそイメージを入手することができました。
本当にDockerイメージが入手できているか確認
powershell$ docker image lspowershellREPOSITORY TAG IMAGE ID CREATED SIZE ruby 2.5.1 ...略以上のような動作結果になりました。Ruby 2.5.1のDockerイメージを正しく入手できたようです。
Dockerコンテナの作成
powershell$ docker container run -it --name RailsTutorialTest -p 8080:3000 -v C:\mountpoint\rails_tutorial_test:/var/www ruby:2.5.1 /bin/bashWindowsのパスワードの入力を要求されるので入力します。WindowsへのログオンにMicrosoftアカウントを使っている場合、Microsoftアカウントのパスワードを打ち込みます。
docker container run
のオプション
-it
…ホスト側の標準入出力とDockerコンテナの標準入出力を接続する
-i
…ホスト側の標準入力とDockerコンテナの標準入力を接続する-t
…Dockerコンテナの標準出力とホスト側の標準出力を接続する- ホスト側からDockerコンテナ上のシェルを操作するために必要な設定
-p {ホスト側TCPポート}:{コンテナ側TCPポート}
- ホスト側の指定TCPポートとコンテナ側の指定TCPポートの間で転送を行わせる
-p 8080:3000
…ホスト側のTCP8080番ポートとコンテナ側のTCP3000番ポートの間で転送を行わせる
- Ruby on Railsのdevelopmentは、初期設定でTCP3000番ポートを使用する
--name {コンテナの名前}
- Dockerコンテナの識別に使う名前をつける
- このオプションがない場合、ランダムな文字列から名前が生成される
- コンテナを識別する方法としては、名前以外に以下の方法がある
- 長いUUID…
f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778
等- 短いUUID…
f78375b1c487
等-v {ホスト側ディレクトリ}:{コンテナ側ディレクトリ}
- コンテナが実行されているホスト側ディレクトリを、コンテナ側ディレクトリとしてマウントする
- ホスト側がWindows系のファイルシステムの場合、パスのディレクトリ区切り文字は
\
である- 使用するイメージ名
- オプションの後に入力する
- 今回は
ruby:2.5.1
である- コンテナで最初に実行するコマンド
- 使用するイメージ名の後に入力する
- 今回は
/bin/bash
であるDockerのShared Driveがノートンのファイアウォールで遮断されないようにする
最初の実行では、以下のエラーが発生し、Dockerコンテナを作成できませんでした。どうやら、システムにインストールされているファイアーウォール機能によってDockerのShared Driveが遮断されている、ということのようです。
powershell...略...docker.exe: Error response from daemon: Drive sharing seems blocked by a firewall.私のWindows PCには、Norton Internet Securityがインストールされています。ということで、DockerのShared Driveがノートンのファイアウォールに引っかからないようにする - gfonius.netによれば、Windows上のファイルやフォルダーをDockerコンテナにマウントするためには、以下の設定内容を変更する必要があるようです。
- Windows 10の[ローカル グループ ポリシー]
- Nortonファイアウォールの[デバイスの信頼]
gfonius.net記載の情報を参考に、以下の設定を変更します。
- Windows 10の[ローカル グループ ポリシー]から、[コンピューターの構成 - Windowsの設定 - セキュリティの設定 - ネットワーク リスト マネージャー ポリシー - 識別されていないネットワーク]を選択→[場所の種類]を[プライベート]に変更
- Norton Internet Securityから、[設定 - ファイアウォール - デバイスの信頼… 設定する]→ともに適当な名前で構わないので、以下2つのIPアドレスの[信頼レベル]に[完全な信頼]を設定
- 10.0.75.0
- 10.0.75.1
以上で、Dockerコンテナを作成できるようになるはずです。
結果
改めてDockerコンテナの作成コマンドを実行すると、今度こそDockerコンテナを作成することができました。powershellのウィンドウ上で、コンテナのbashが動いています。
bashroot@...略...:/#関連リンク
- DockerでRailsチュートリアル(環境構築編) - 桜色HelloWorld - 行ったことは、ほぼこちらの後追いです。
- 投稿日:2019-07-10T22:48:51+09:00
raspberrypi3にdockerをインストール
***追記
下記の手順でインストールはできたが、
実行時に下記のエラーが発生して、
実行できなかった。docker: Error response from daemon: unable to find "net_prio" in controller set: unknown.
docker側の対応待ちのよう
https://github.com/docker/for-linux/issues/545
まずは、下記のサイト通り、
下記のコマンドを実行。curl -sSL https://get.docker.com | sh
エラーメッセージが表示されて、
インストールできなかった。・エラーメッセージ
E: Repository 'http://raspbian.raspberrypi.org/raspbian buster InRelease' changed its 'Suite' value from 'testing' to 'stable'下記のコマンドを実行したらいいとあったので、
実行する。sudo apt-get update --allow-releaseinfo-changeやっぱりエラーが出力される。
・エラーメッセージ
E: リポジトリ https://download.docker.com/linux/raspbian 10 Release には Release ファイルがありません。
https://www.nekochango.com/entry/linux/trouble/apt-get_bionic_release_nothingとりあえず、
dockerのインストールコマンドを実行してみる。sudo apt-get install -y docker.io正常にインストールされた。
sudo docker --version
- 投稿日:2019-07-10T19:01:03+09:00
Ubuntu16の公式Dockerイメージには/etc/servicesや/etc/protocolsが入っていない
Ubuntu16の公式Dockerイメージには/etc/servicesや/etc/protocolsが入っていない
初期状態では一部のネットワーク系API(getprotobynameとかgetaddrinfoとか)が失敗する。
ネットワーク系のアプリやライブラリを使う際にエラーが起きると、原因究明に難渋する場合がある。
(こんなファイルがないとか、なかなか想像しないですよね?)対策
問題のファイル群は
netbase
パッケージに含まれている模様。入れましょう。sudo apt install netbase問題の実例
例えば、こんな問題が起きた:
メッセージキューのライブラリであるQpid Protonを使用。
通信先のポート番号を明示的に指定した場合は問題なく動くが、明示指定しないと処理が永久に進まなくなるという不具合が発生。調べたところ、以下の機序で無限ループしていた。
- Qpid ProtonがAMQPのデフォルトポート番号をgetaddrinfo()で解決しようとする
- /etc/servicesがないので、APIが失敗
- Qpid Protonが(なぜか)失敗時に無限にリトライする実装になっているため、最初に戻る
その他
Ubuntu16のdockerイメージの他、それをベースにしたdockerイメージにも入っていない場合があるので注意。
Ubuntu16ベースのNVIDIA cudaイメージとか。
Dockerfileを書くときはパッケージを--no-install-recommendsで入れることが多いので、依存関係による自動導入もされにくい。Ubuntuをミニマム構成でインストールした場合にも入らないかも?(未確認)。
ぐち
これくらい最初から入れといてくれてもいいのに…
(障害票の閉じられ方を見るに、by designなのか?)
- 投稿日:2019-07-10T17:26:09+09:00
(Failed to) Show docker load progress bar over SSH
SSH上でもdocker loadのプログレスバーを表示したかった(失敗)
Introduction
I often load large (several gigabytes) docker images over SSH. Locally I can see progress bar saying "Loading layer". However the it is gone when docker is loaded over SSH.
Method and Result
Understanding internal state
Firstly I analyzed docker.sock packet. Since unix domain socket is used to communicate with docker backend, usual wireshark does not work well. So, after
sudo mv /var/run/docker.sock /var/run/docker.sock.temp
, I used two proxies to utilize wiresharktcp.port == 10000
.sudo socat UNIX-LISTEN:/var/run/docker.sock,mode=777,reuseaddr,fork TCP-CONNECT:localhost:10000 socat -v TCP-LISTEN:10000,fork UNIX-CONNECT:/var/run/docker.sock.tempThen, while I
ssh localhost docker load < img.tar
, in wireshark I seePOST /v1.30/images/load?quiet=1 HTTP/1.1
packet. This indicates that quiet mode was specified even though I'm not specifying-q
.Understanding the call stack
[backend] components/engine/image/tarexport/load.go Load() components/engine/daemon/image_exporter.go LoadImage() components/engine/api/server/router/image/image_routes.go postImagesLoad() [frontend] components/cli/cli/command/image/load.go runLoad()Now I understand that runLoad()'s
dockerCli.Out().IsTerminal()
controls the state.How is the terminal checked?
In components/engine/pkg/term/term.go
IsTerminal()
, I seereturn tcget(fd, &termios) == 0
. If this condition becomes true, the console output should be recognized as terminal.Conclusion
I found that tcget is the key to get the progress bar back. But I cannot find how to achieve it yet. This is not a personal project, so (unlike cTouch's safariextz signing date hack) custom LD_PRELOAD cannot be used. I also tried unbuffer as described in https://unix.stackexchange.com/questions/249723/how-to-trick-a-command-into-thinking-its-output-is-going-to-a-terminal , but it does not work well either. Suggestions are welcomed...
- 投稿日:2019-07-10T17:26:09+09:00
Show docker load progress bar over SSH
SSH上でもdocker loadのプログレスバーを表示する
Introduction
I often load large (several gigabytes) docker images over SSH. Locally I can see progress bar saying "Loading layer". However the it is gone when docker is loaded over SSH.
Method and Result
Understanding internal state
Firstly I analyzed docker.sock packet. Since unix domain socket is used to communicate with docker backend, usual wireshark does not work well. So, after
sudo mv /var/run/docker.sock /var/run/docker.sock.temp
, I used two proxies to utilize wiresharktcp.port == 10000
.sudo socat UNIX-LISTEN:/var/run/docker.sock,mode=777,reuseaddr,fork TCP-CONNECT:localhost:10000 socat -v TCP-LISTEN:10000,fork UNIX-CONNECT:/var/run/docker.sock.tempThen, while I
ssh localhost docker load < img.tar
, in wireshark I seePOST /v1.30/images/load?quiet=1 HTTP/1.1
packet. This indicates that quiet mode was specified even though I'm not specifying-q
.Understanding the call stack
[backend] components/engine/image/tarexport/load.go Load() components/engine/daemon/image_exporter.go LoadImage() components/engine/api/server/router/image/image_routes.go postImagesLoad() [frontend] components/cli/cli/command/image/load.go runLoad()Now I understand that runLoad()'s
dockerCli.Out().IsTerminal()
controls the state.How is the terminal checked?
In components/engine/pkg/term/term.go
IsTerminal()
, I seereturn tcget(fd, &termios) == 0
. If this condition becomes true, the console output should be recognized as terminal.Conclusion
I found that tcget is the key to get the progress bar back. But I cannot find how to achieve it yet. This is not a personal project, so (unlike cTouch's safariextz signing date hack) custom LD_PRELOAD cannot be used. I also tried unbuffer as described in https://unix.stackexchange.com/questions/249723/how-to-trick-a-command-into-thinking-its-output-is-going-to-a-terminal , but it does not work well either. Suggestions are welcomed...
PS
angel_p_57's method worked like a charm!
- 投稿日:2019-07-10T16:58:36+09:00
kubernetesでpodのstatusがREADY 0/1になっててどうすればいいか分からなくて困った、というかログの確認方法が分からなかった
はじめに
kubernetes触り始めました!!
全然興味なかったんですけどやってみると楽しいですね。
結局どんなアプリケーションを動かすかが大事だと思ってたんでインフラ系は興味ナッシンだったのですが、環境つくるの楽しい。まだはじめの一歩どころか小指の爪切ったくらいのレベルなんですけども。で、色々チュートリアルしたりしてたんですけど、PodがRunningにならないの。。
どうすればいいか分からなくて泣いた。
Errorログどこに出るの
私もね、一応SEなんでね、ログをみて原因を探ろうとしましたよ。
さすがにログも見ないで助けを求めちゃうようなゆとり社員じゃないですから。
どこでログみるの!!??
結局ログ見ないまま先輩に聞きました。
エラーログの出し方
ということで学んだ内容を共有します。
kubernetesでは、ログを出すとき以下2つのコマンドが使えます。1個目: logs
コンテナが出力しているログを確認する方法。コンテナ内で起動してるアプリケーションに原因がある場合はこちら。2個目: describe
podのイベントを出力する。メモリ足りない!とかマウント失敗!などのkubernetesの設定に問題がある場合はこちら。流れとしては、問題のあるpodの名前を調べて、上記のコマンドを実行します。
まずは調べたいpodの名前を調べます。
$ kubectl get po NAME READY STATUS RESTARTS AGE guestbook-v1-544fbbc99b-d 0/1 Pending 0 23hpoはpodの短縮名称です。短縮名知ったら使いたくなる。
上記の例だと、guestbook-v1-544fbbc99b-d がpodの名前です。podの名前が分かったので、describeないしlogsコマンドでログをGETできます。
$ kubectl describe pod guestbook-v1-544fbbc99b-d $ kubectl logs guestbook-v1-544fbbc99b-d47t5describeの場合は、リソースタイプを指定する必要があるので、pod [pod名]と指定する必要があります。
pod以外でも、リソースタイプを指定すればログをとれます。$ kubectl describe pv pv名 $ kubectl describe svc サービス名などなど。
参考
エラーの原因がわかった後は、以下の記事を参考に解決すると良いかも。
Kubernetesのポッドが起動しない原因と対策さいごに
kubernetes楽しい。名前変だし勝手に避けてたけど、だんだん名前もかっこよく思えてきた。
けどやっぱり、開発のが楽しいかな。。
どこで動かすかより、何を動かすかのが大事だよね。。
一生畑を耕して、野菜植えないみたいなことにはなりたくないので、私は耕し屋さんではなく、野菜を育てるところまで頑張って、立派な農家を目指したいと思います!!
- 投稿日:2019-07-10T15:15:05+09:00
PostgresのDBバックアップ・リストア簡易検証手順
docker-compose.yml
を使ってPostgresインスタンス起動。
- mydb1: バックアップ対象のインスタンス
- mydb2: リストア先のインスタンス
docker-compose.ymlversion: '3.1' services: mydb1: image: postgres:9.6 restart: always environment: POSTGRES_DB: example1 POSTGRES_USER: example POSTGRES_PASSWORD: example ports: - '15432:5432' mydb2: image: postgres:9.6 environment: POSTGRES_DB: example2 POSTGRES_USER: example POSTGRES_PASSWORD: example ports: - '25432:5432'Postgresインスタンスの起動
docker-compose upテスト用にデータを投入する。
psql -U example -h localhost -p 15432 -d example1 > create table users(id serial primary key, name varchar); > insert into users (name) values ('hanako'), ('taro');mydb1をバックアップする
pg_dump -U example -h localhost -p 15432 -d example1 > exmple1.dumpmydb2にリストアする
psql -U example -h localhost -p 25432 -d example2 -f exmple1.dumpリストア後の確認
psql -U example -h localhost -p 25432 -d example2 > select * from users; |id|name | |--|------| | 1|hanako| | 2|taro |
- 投稿日:2019-07-10T12:29:22+09:00
AWS ECS向けCloudWatch Container Insightsのパブリックプレビューが開始したので、使用開始方法をまとめてみた
はじめに
こんにちわ。Wano株式会社エンジニアのnarikawaと申します。
/
— ポジティブな Tori (@toricls) July 10, 2019
Amazon ECS 向けの CloudWatch Container Insights のパブリックプレビューを開始しました!!
\
/ "Introducing Amazon CloudWatch Container Insights for Amazon ECS and AWS Fargate - Now in Preview" https://t.co/b1jaSGtg3x
個人的にはこっちの手順が分かり易かったです!https://t.co/UXiIwErG5B
— nari@エンタメ系エンジニア (@fukubaka0825) July 10, 2019ということで、以下の手順書を参考に試しに設定してみました。
Amazon ECS CloudWatch Container Insights - Amazon Elastic Container Service
ところどころわかりづらいところがあったり、日本語訳が提供されていないこともあったので、整理して発信しようと思い、この記事を書いています。
全てを訳せているわけではないので、詳細は大元の手順書を参考にしていただけると幸いです。対象読者
- CloudWatch Container Insightsの設定が、プレビュー時に使っていなくてよくわからない方
- 手順書が英語しか対応していないため嫌厭してまだ試せていない方
- CloudWatch Container Insightsでどんなことができるか知りたい方
導入手順
1.まずは設定いじる
GUI(console)で設定する
※この際、ルートユーザーまたはコンテナーインスタンスのIAMロールを使用していることが前提
※この際、実行しようとしているIAM usersとIAM role はecs:PutAccountSetting permissionがこのアクションに必要
CUIで設定する
- 自分のアカウント全てのIAM usersとIAM roleのdefaultの設定をcontainer insightsをenabledにしたい
put-account-setting-default (AWS CLI)の場合
aws ecs put-account-setting-default --name containerInsights --value enabled --region us-east-1Write-ECSAccountSettingDefault (AWS Tools for Windows PowerShell)の場合
Write-ECSAccountSettingDefault -Name containerInsights -Value enabled -Region us-east-1 -Force
- 自分のアカウントのあるIAM usersとIAM roleのdefaultの設定をcontainer insightsをenabledにしたい(root userのみ)
put-account-setting (AWS CLI)の場合(特定のuser設定変更)
aws ecs put-account-setting --name containerInsights --value enabled --principal-arn arn:aws:iam::aws_account_id:user/userName --region us-east-1Write-ECSAccountSetting (AWS Tools for Windows PowerShell)の場合(特定のuser設定変更)
Write-ECSAccountSetting -Name containerInsights -Value enabled -PrincipalArn arn:aws:iam::aws_account_id:user/userName -Region us-east-1 -Force2.クラスターを作る
3.いつも通りサービスかタスクを立ち上げる
4.誘導に従って、cloudwatchのcontainer insightsを見る
- クラスタのメトリクスのタブに移動すると、見慣れない青枠の誘導があるので、View Container Insightsのボタンをクリックする
- そうすると以下のような、docker stats相当の情報が観れる
container insightsのいいところ
- コンテナインスタンスにsshして、docker statsしなくてもコンテナの状態を監視できる
疑問点
- まだterraformでは対応していない?
- public previewだから多分対応していない
- clusterのパラメタで早く切り替えれると嬉しい。。
- 既存のクラスタをいじって設定を足せないのか
- terraformで建ててから手動で切り替えようと思ったらできなかった(そもそもクラスターの設定修正画面がない)
- CLIならいけるのか??
- ecs — AWS CLI 1.16.195 Command Reference 見当たらない、、
わかる方ぜひ教えて欲しいです、、わりと切実- [追記 2019/7/10]以下の回答いただけました!、正式なリリースでの対応が待ち遠しい
ありがとうございます!
— ポジティブな Tori (@toricls) July 10, 2019
既存クラスタでの有効化は現時点ではできないので新規クラスタでお試しいただく感じになります?終わりに
- 週1投稿に関して、これは先週分ってことで許してください(遅れてすみません。。)
- 投稿日:2019-07-10T11:46:27+09:00
Hello Docker するだけの Docker Image を作る
Docker 触ったことない人向け。
Dockerfile を書く心理的障壁を下げることを目的とする記事です。docker コマンドがインストール済であることを前提としています。
インストールがまだの人はこちらをご参照の上、インストールお願いします。https://docs.docker.com/get-started/Dockerfile
今回、実行環境は Ubuntu を使うことにします。
Version は xenial を使うことにします。Ubuntu の Version およびサポート期間などは以下を参照。
https://www.ubuntulinux.jp/ubuntuDockerfile から参照する Ubuntu の Docker Image
https://hub.docker.com/_/ubuntuDockerfileFROM ubuntu:xenial RUN echo "Now building..." CMD echo "Hello Docker"Docker Image 作成
docker build <image name> <dir path>
コマンドを実行。
<dir path>
には Image に固める file が配置されているパスを指定します。$ cd <Dockerfile が配置されているディレクトリ> $ docker build -t helloworld . Sending build context to Docker daemon 2.048kB Step 1/3 : FROM ubuntu:xenial ---> 7e87e2b3bf7a Step 2/3 : RUN echo "Now building..." ---> Using cache ---> 5045cdd6bdcd Step 3/3 : CMD echo "Hello Docker" ---> Using cache ---> 87c1c9ff264e Successfully built 87c1c9ff264e Successfully tagged helloworld:latestHello Docker
docker run <image name>
コマンドを実行。$ docker run helloworld Hello Docker
以下のようにすると
docker run
時に起動したコンテナの bash セッションを生成することができます。$ docker run -it helloworld /bin/bash root@b48d469b6a68:/#参考
- 投稿日:2019-07-10T07:54:14+09:00
DockerHubで公開されているコンテナが安全か確かめてみた結果【人気のコンテナ上位800個】
はじめに
Docker Hubに公開されているイメージはどの程度安全なのか、 Dockle
と Trivy
を利用して検証しました。
検証結果は、 https://containers.goodwith.tech/ に公開しています。結論
基本的にどのコンテナにも脆弱性はある!
人気が高いコンテナ/最近ビルドされているコンテナでも関係ない!ただ、Docker公式が用意しているコンテナは今のところ大丈夫。
より詳しいことを知りたい人は 操作方法 を見て、 https://containers.goodwith.tech/ を操作してみてください。操作方法
① ソートやフィルタが簡単にできます
※ Scoreは脆弱性のCVSSスコアなどを元にした参考値です。指標を一つに統一したかったので作りました。
ガチ勢の方々、怒らないでください & よりよい指標をつくるためのアドバイスをください。② Dockle, Trivy というカラムを選択すると、JSON形式で詳細な情報が表示されます
③ JSONのロードが遅いときは「JSON Detail」のリンクからダウンロードできます
※ netlifyを利用してるんですが、特に大きいJSONファイルの取得が遅いので、解決方法を知りたいです
何がチェックできるの?
CISベンチマークに沿っているかチェックできます。CIS(The Center for Internet Security)のセキュリティ専門家たちが発行している資料です。
簡単に言うと、Dockleの列ではイメージの設計が正しくされているか、Trivyの列では脆弱性のあるパッケージが使われていないかをチェックできます。
その他にも、パスワードが設定されていないユーザのチェックなど、Linuxの基礎的なセキュリティもチェックします。
ただし、すべてのコンテナで警告が出てしまうので、「latestタグはやめよう」「Content Trustを有効にしよう」の2項目は無視しています。
データの作り方
過去に記事にした Dockle
と Trivy
を利用しています。
対象のコンテナイメージに対してそれぞれスキャンしていき、結果を集計しました。なお800個のコンテナを平行処理して1時間掛かりませんでした。
- Dockle関連記事
- Trivy関連記事
なお、私はDockleの作者で、Trivyのメインコミッタの一人です。GitHub Starが増えると喜びます。
フロントエンドやホスト環境は?
メインで使っているライブラリは以下のものです。
Docker Meetup Tokyo #31のLTに間に合わせるべく、画面のベース作成1日というギリギリのスケジュールだったためCreate React Appを利用しました。
- Create React App
- ag-Grid : テーブル
├── public : JSONや画像など ├── src : ソースコード └── yarn.lockフォルダ構成は現在このようになっており、すべてnetlifyでホストされています。
ただ、ファイルサイズが大きくなるとnetlifyだと極端に遅くなります。
特に脆弱性の数が多いJSONデータのロードで顕著です。解決策があれば教えてください。脆弱性対策はどうすればいい?
ここや、この記事の後半でお伝えしたとおり、どのように向き合うかは、そのサービスの用途や求めるレベルによります。
ただ、Trivyで検出された脆弱性については、新しいOSにして新しいバージョンのパッケージを入れたら脆弱性は減るので、公開されているDockerfileを元に自らの手で書き直すことをおすすめします。
脆弱性についてより詳しいことが気になった人は、私も参加しているプロジェクト Vulsのチームが主催する 「既知の脆弱性はこう捌け!」系の勉強会に参加すると、体系的に学ぶ事ができます。
最後に
最初に、Docker公式が用意しているイメージが今のところ大丈夫と伝えました。
しかし、いつ脆弱性が入るのかはわからないので、ビルドごとにイメージのチェックすることをおすすめします。実例として、今年の5月まで公式が用意したAlpine LinuxのイメージにRootユーザのパスワードが設定されていないという脆弱性がありました。ローカルビルドの際に、すでにあるイメージを毎回参照していて、過去の脆弱性をそのまま使い続けている状況もありえます。ローカルでイメージを作成している人/コンテナのイメージをキャッシュから作成されている方は、特に一度スキャンすることをおすすめします。
なお、今後も https://containers.goodwith.tech/ に、ユーザーの入力したイメージ名からスキャンをするなど、機能追加していく予定です。 フッターにシェアボタン付けたので、シェアお願いします?
- 投稿日:2019-07-10T07:54:14+09:00
DockerHubで公開されているコンテナが安全か確かめてみた【人気のコンテナ上位800個!】
はじめに
Docker Hubに公開されているイメージはどの程度安全なのか、 Dockle
と Trivy
を利用して検証しました。
検証結果は、 https://containers.goodwith.tech/ に公開しています。結論
基本的にどのコンテナにも脆弱性はある!
人気が高いコンテナ/最近ビルドされているコンテナでも関係ない!ただ、Docker公式が用意しているコンテナは今のところ大丈夫。
より詳しいことを知りたい人は 操作方法 を見て、 https://containers.goodwith.tech/ を操作してみてください。操作方法
① ソートやフィルタが簡単にできます
※ Scoreは脆弱性のCVSSスコアなどを元にした参考値です。指標を一つに統一したかったので作りました。
ガチ勢の方々、怒らないでください & よりよい指標をつくるためのアドバイスをください。② Dockle, Trivy というカラムを選択すると、JSON形式で詳細な情報が表示されます
③ JSONのロードが遅いときは「JSON Detail」のリンクからダウンロードできます
※ netlifyを利用してるんですが、特に大きいJSONファイルの取得が遅いので、解決方法を知りたいです
何がチェックできるの?
CISベンチマークに沿っているかチェックできます。CIS(The Center for Internet Security)のセキュリティ専門家たちが発行している資料です。
簡単に言うと、Dockleの列ではイメージの設計が正しくされているか、Trivyの列では脆弱性のあるパッケージが使われていないかをチェックできます。
その他にも、パスワードが設定されていないユーザのチェックなど、Linuxの基礎的なセキュリティもチェックします。
ただし、すべてのコンテナで警告が出てしまうので、「latestタグはやめよう」「Content Trustを有効にしよう」の2項目は無視しています。
データの作り方
過去に記事にした Dockle
と Trivy
を利用しています。
対象のコンテナイメージに対してそれぞれスキャンしていき、結果を集計しました。なお800個のコンテナを平行処理して1時間掛かりませんでした。
- Dockle関連記事
- Trivy関連記事
なお、私はDockleの作者で、Trivyのメインコミッタの一人です。GitHub Starが増えると喜びます。
フロントエンドやホスト環境は?
メインで使っているライブラリは以下のものです。
Docker Meetup Tokyo #31のLTに間に合わせるべく、画面のベース作成1日というギリギリのスケジュールだったためCreate React Appを利用しました。
- Create React App
- ag-Grid : テーブル
├── public : JSONや画像など ├── src : ソースコード └── yarn.lockフォルダ構成は現在このようになっており、すべてnetlifyでホストされています。
ただ、ファイルサイズが大きくなるとnetlifyだと極端に遅くなります。
特に脆弱性の数が多いJSONデータのロードで顕著です。解決策があれば教えてください。脆弱性対策はどうすればいい?
ここや、この記事の後半でお伝えしたとおり、どのように向き合うかは、そのサービスの用途や求めるレベルによります。
ただ、Trivyで検出された脆弱性については、新しいOSにして新しいバージョンのパッケージを入れたら脆弱性は減るので、公開されているDockerfileを元に自らの手で書き直すことをおすすめします。
脆弱性についてより詳しいことが気になった人は、私も参加しているプロジェクト Vulsのチームが主催する 「既知の脆弱性はこう捌け!」系の勉強会に参加すると、体系的に学ぶ事ができます。
最後に
最初に、Docker公式が用意しているイメージが今のところ大丈夫と伝えました。
しかし、いつ脆弱性が入るのかはわからないので、ビルドごとにイメージのチェックすることをおすすめします。実例として、今年の5月まで公式が用意したAlpine LinuxのイメージにRootユーザのパスワードが設定されていないという脆弱性がありました。ローカルビルドの際に、すでにあるイメージを毎回参照していて、過去の脆弱性をそのまま使い続けている状況もありえます。ローカルでイメージを作成している人/コンテナのイメージをキャッシュから作成されている方は、特に一度スキャンすることをおすすめします。
なお、今後も https://containers.goodwith.tech/ に、ユーザーの入力したイメージ名からスキャンをするなど、機能追加していく予定です。 フッターにシェアボタン付けたので、シェアお願いします?
- 投稿日:2019-07-10T07:54:14+09:00
DockerHubで公開されているコンテナが安全か確かめてみた結果【人気のコンテナ上位800個!】
はじめに
Docker Hubに公開されているイメージはどの程度安全なのか、 Dockle
と Trivy
を利用して検証しました。
検証結果は、 https://containers.goodwith.tech/ に公開しています。結論
基本的にどのコンテナにも脆弱性はある!
人気が高いコンテナ/最近ビルドされているコンテナでも関係ない!ただ、Docker公式が用意しているコンテナは今のところ大丈夫。
より詳しいことを知りたい人は 操作方法 を見て、 https://containers.goodwith.tech/ を操作してみてください。操作方法
① ソートやフィルタが簡単にできます
※ Scoreは脆弱性のCVSSスコアなどを元にした参考値です。指標を一つに統一したかったので作りました。
ガチ勢の方々、怒らないでください & よりよい指標をつくるためのアドバイスをください。② Dockle, Trivy というカラムを選択すると、JSON形式で詳細な情報が表示されます
③ JSONのロードが遅いときは「JSON Detail」のリンクからダウンロードできます
※ netlifyを利用してるんですが、特に大きいJSONファイルの取得が遅いので、解決方法を知りたいです
何がチェックできるの?
CISベンチマークに沿っているかチェックできます。CIS(The Center for Internet Security)のセキュリティ専門家たちが発行している資料です。
簡単に言うと、Dockleの列ではイメージの設計が正しくされているか、Trivyの列では脆弱性のあるパッケージが使われていないかをチェックできます。
その他にも、パスワードが設定されていないユーザのチェックなど、Linuxの基礎的なセキュリティもチェックします。
ただし、すべてのコンテナで警告が出てしまうので、「latestタグはやめよう」「Content Trustを有効にしよう」の2項目は無視しています。
データの作り方
過去に記事にした Dockle
と Trivy
を利用しています。
対象のコンテナイメージに対してそれぞれスキャンしていき、結果を集計しました。なお800個のコンテナを平行処理して1時間掛かりませんでした。
- Dockle関連記事
- Trivy関連記事
なお、私はDockleの作者で、Trivyのメインコミッタの一人です。GitHub Starが増えると喜びます。
フロントエンドやホスト環境は?
メインで使っているライブラリは以下のものです。
Docker Meetup Tokyo #31のLTに間に合わせるべく、画面のベース作成1日というギリギリのスケジュールだったためCreate React Appを利用しました。
- Create React App
- ag-Grid : テーブル
├── public : JSONや画像など ├── src : ソースコード └── yarn.lockフォルダ構成は現在このようになっており、すべてnetlifyでホストされています。
ただ、ファイルサイズが大きくなるとnetlifyだと極端に遅くなります。
特に脆弱性の数が多いJSONデータのロードで顕著です。解決策があれば教えてください。脆弱性対策はどうすればいい?
ここや、この記事の後半でお伝えしたとおり、どのように向き合うかは、そのサービスの用途や求めるレベルによります。
ただ、Trivyで検出された脆弱性については、新しいOSにして新しいバージョンのパッケージを入れたら脆弱性は減るので、公開されているDockerfileを元に自らの手で書き直すことをおすすめします。
脆弱性についてより詳しいことが気になった人は、私も参加しているプロジェクト Vulsのチームが主催する 「既知の脆弱性はこう捌け!」系の勉強会に参加すると、体系的に学ぶ事ができます。
最後に
最初に、Docker公式が用意しているイメージが今のところ大丈夫と伝えました。
しかし、いつ脆弱性が入るのかはわからないので、ビルドごとにイメージのチェックすることをおすすめします。実例として、今年の5月まで公式が用意したAlpine LinuxのイメージにRootユーザのパスワードが設定されていないという脆弱性がありました。ローカルビルドの際に、すでにあるイメージを毎回参照していて、過去の脆弱性をそのまま使い続けている状況もありえます。ローカルでイメージを作成している人/コンテナのイメージをキャッシュから作成されている方は、特に一度スキャンすることをおすすめします。
なお、今後も https://containers.goodwith.tech/ に、ユーザーの入力したイメージ名からスキャンをするなど、機能追加していく予定です。 フッターにシェアボタン付けたので、シェアお願いします?
- 投稿日:2019-07-10T04:02:22+09:00
DockerでGitLabとDB2のコンテナを起動するコマンド覚書
GitLabを起動する
docker-compose.ymlweb: image: 'gitlab/gitlab-ce:latest' restart: always hostname: 'localhost' environment: GITLAB_OMNIBUS_CONFIG: | external_url 'http://localhost:9010' gitlab_rails['gitlab_shell_ssh_port'] = 2022 ports: - '9010:9010' - '2022:22' volumes: - '/srv/gitlab/config:/etc/gitlab' - '/srv/gitlab/logs:/var/log/gitlab' - '/srv/gitlab/data:/var/opt/gitlab'DB2を起動する
ディレクトリ構成
/docker-compose.yml
/db/DockerfileDockerfile
FROM ibmcom/db2express-c:latestdocker-compose.ymldb2: container_name: mydb2 ports: - '50000:50000' environment: - LICENSE=accept - DB2INST1_PASSWORD=password - DBNAME=testdb volumes: - '/db2:/database' image: ibmcom/db2起動コマンド
docker-compose up
※微調整が必要な可能性あり
- 投稿日:2019-07-10T01:17:09+09:00
フロント「Vue + gRPC-Web」、サーバー「Python + gRPC」構成でタイマーアプリを作る。
概要
REST APIより良いAPIの通信方法はないものか調べていたら、gRPCというものが見つかりました。なかなか良さそうなので簡単なアプリを作りながら、使った感じをメモします。
結論を先に言うと、Pythonでサーバー作るのちょっときついかも。。でした。
期待していた、messageの補完が効かないからです。gRPCってなに
gRPCはRPC実装の一つです。
RPCとはなにかといういうと、REST APIの弱点を克服する通信規格のひとつです。
RESTの辛みを解消した、代替候補の1つという認識です。REST APIとの大きな違いとしては、引数や返り値のデータ型をしっかり決める必要があることかな、と。
これの何が嬉しいかというと、APIの引数、返り値を編集したり使用するときに補完が効く(はず)ということ。
APIの構造を決めればデータ型は自動生成する機能もついています。
なので、仕様書を見ながらこの項目は文字型だ、数字型だということを気にしなくてもよく、より実装=仕様な感じになるのではないかなと。あと、サーバーとの双方向通信(プッシュ型)の処理もできるのは期待大です。
もうポーリングする必要ないんです!RPC(Remote Procedure Call)の名前が示す通り、REST APIよりも、関数を呼ぶ感覚で使える感じですね。
やってみる
作るもの
タイマーを作ってみます。
フロントVue, サーバーPythonの構成でgRPC通信します。
別にサーバーなくても作れる内容なんですが、とにかくgRPCを無理やり使うんです。それがサンプルプログラムってもんです。
仕様
- タイマー機能はサーバーに持つ。
- フロントからタイマー開始の命令をgRPC経由で送る。
- サーバーからは1秒おきに残り時間をgRPC経由でフロントに送る。
- フロントはサーバーから送られてきた残り時間を画面に表示する。
作ったものをGitHubに上げています。
試した環境(前提)
- Windows 10
- Python 3.6
- Node.js 12.5.0
- npm 6.9.0
- yarn 1.9.4
- Docker for Windows 2.0.0.3 (envoy用)
(余談)Docker初めて使いましたが、死ぬほど便利ですね。
環境構築
必要なツールを入れていきます。
Vueをインストール
フロントはVueで作るので、Vueのツールをインストールします。
npm install -g @vue/cliここを参考にさせていただきました。
Protocol Buffer のコンパイラの準備
gRPCでは、APIの仕様の記述をProtocol Buffersというインターフェース定義用言語を使います。
Protocol Buffersは、雑な例えをすると、SQLのCREATE TABLE構文だけ抜き出したもの+関数インターフェース定義ができる言語、みたいな印象です。
Protocol Buffersで書いたデータ定義や関数定義を各言語にコンパイルするため,言語別のコンパイラをインストールします。
今回はjavascript用とPython用です。javascript用(gRPC-web)コンパイラのインストール
手動で入れます。
コンパイラ本体とjavascript用プラグインをダウンロードして、中に入っている実行ファイル(
protoc.exe
、protoc-gen-grpc-web.exe
)にそれぞれパスを通す。インストールされたか確認するには、
protoc --version libprotoc 3.8.0となればとりあえずOK。
javascript用ですが、Typescript定義ファイルも一緒に吐き出せます。やった。ここの手順は公式チュートリアルのここらへんを参考にしています。
Python用コンパイラのインストール
pip install grpcio-toolsインストールされたか確認するには、
python -m grpc_tools.protoc --version libprotoc 3.8.0となればOK。
疑問だった点。
何でweb用とpython用でコンパイラの入れ方が違うのだろう。。
個人的には、python用もprotoc-gen-python.exe みたいなプラグインにして、コンパイラ本体は共通にしてほしかったです。
どうやらpipでインストールしたほうもprotocコンパイラの本体(をdllにしたもの)が別途ダウンロードされているようなので、クライアントとサーバーでバージョンが異なったりしないのかモヤモヤします。APIの実装
Protocol Buffersを実装していきます。
timer.protosyntax = "proto3"; package timer_with_grpc; service Timer { rpc StartTimer(StartRequest) returns (stream TimerState); // タイマー開始 rpc StopTimer(Empty) returns (TimerState); // タイマー停止 } message StartRequest { int32 time = 1; } message TimerState { bool isRunning = 1; int32 leftTime = 2; } // 引数空ができないようなので、空用の定義をしておく message Empty { }シンプル。
基本的な定義はサンプルの書き換えで何とかなりそうな印象です。
service
の中にAPIのインターフェースを定義し、message
で引数や返却値のデータ構造を定義しています。
ここではStartTimer
とStopTimer
の2つのAPIを定義しています。
引数がいらないAPIもありそうですが、rpc StopTimer() returns (TimerState);としてみたらエラーになったので、何かしら引数はいるみたいです。
今回はEmpty
という空のデータ型を定義してみました。
良い方法かどうかはわかりません。また、returns に
stream
をつけるとサーバーからデータをプッシュ型でクライアントに送信できます。これがやりたかった。Protocol Buffersのコンパイル
クライアント用コード生成(Javascript + Typescript定義ファイル)
protoc -I=. timer.proto --js_out=import_style=commonjs:. --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:.
timer_pb.js
timer_pb.d.ts
timer_grpc_web_pb.js
timer_grpc_web_pb.d.ts
という4つのファイルが出力されました。
オプション次第でちゃんとTypescriptの定義ファイルまで出してくれるのでありがたいですね。(+dtsをつける)
内容結構ごつくてちゃんと読めてませんが、timer_grpc_web_pb.d.ts
にAPIのクライアントインターフェースらしきものがあることが確認できます。サーバ用コード生成(Python)
python -m grpc_tools.protoc -I. timer.proto --python_out=. --grpc_python_out=.
timer_pb2.py
、timer_pb2_grpc.py
という2つのファイルが出力されました。
timer_pb2_grpc.py
の方にAPI実装のひな型があるので、継承して機能を実装します。サーバー側APIの実装
TimerApi.pyimport timer_pb2 import timer_pb2_grpc from concurrent import futures import time import grpc # APIのロジック class TimerServicer(timer_pb2_grpc.TimerServicer): leftTime = 0 isRunning = False def StartTimer(self, request, context): self.leftTime = request.time self.isRunning = True while self.leftTime > 0: if self.isRunning: # 途中でStopTimerされてないかチェック yield self.makeTimerState() time.sleep(1) self.leftTime -= 1 else: return self.isRunning = False yield self.makeTimerState() def StopTimer(self, request, context): self.isRunning = False return self.makeTimerState() def makeTimerState(self): return timer_pb2.TimerState( isRunning=self.isRunning, leftTime=self.leftTime ) # サーバーの実行 def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) timer_pb2_grpc.add_TimerServicer_to_server(TimerServicer(), server) server.add_insecure_port('0.0.0.0:8082') server.start() print("Server Start!!") try: while True: time.sleep(1) except KeyboardInterrupt: server.stop(0) if __name__ == '__main__': serve()
TimerServicer
がprotocコンパイラが出力したAPIインターフェースを継承して
ロジックを追加した部分です。StartTimerは、引数でもらった秒数だけカウントダウンしていきます。
StopTimerで止めます。クライアント側実装
Vueでプロジェクトを作成
まずはVueの
client
とう名前のプロジェクトを作成します。$ vue create client Vue CLI v3.8.4 ┌───────────────────────────┐ │ Update available: 3.9.2 │ └───────────────────────────┘ ? Please pick a preset: Manually select features ? Check the features needed for your project: TS, CSS Pre-processors ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? No ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass) ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? NoBabelを使用しないで、Typescriptとscssを使うようにした以外はデフォルトで作りました。
コンパイルしてみる。
クライアント用のプロジェクトができたので、いったんコンパイルしてみましょう。
コンパイルのコマンドはclient
ディレクトリに入ってから、yarn serveです
その際、Protocol Buffersのコンパイルした
timer_pb.js
timer_pb.d.ts
timer_grpc_web_pb.js
timer_grpc_web_pb.d.ts
も含めて(client/src以下に4ファイルを置いて)コンパイルしてみると、
以下のようなエラーがでてきました。1:23 Cannot find module 'google-protobuf'. > 1 | import * as jspb from "google-protobuf" | ^ <<中略>> 10:26 Cannot find module 'grpc-web'. > 10 | import * as grpcWeb from 'grpc-web'; | ^
google-protobuf
とgrpc-web
がないと怒られたので、素直にインストールします。yarn add google-protobuf @types/google-protobuf grpc-webあたらめてコンパイルすると、今度は通りました。
実装
App.vue<template> <div id="app"> <p> - TIMER - </p> <br> <p> {{isTimerRunning ? "実行中" : "停止中"}} </p> <p class="time"> {{leftTime}} </p> <button @click="startTimer">start</button> <button @click="stopTimer">stop</button> </div> </template> <script lang="ts"> import {Component, Vue} from 'vue-property-decorator'; import {TimerClient} from "./timer_grpc_web_pb"; import {Empty, StartRequest, TimerState} from "./timer_pb"; import {ClientReadableStream} from "grpc-web"; @Component({}) export default class App extends Vue { private timerClient: TimerClient; private isTimerRunning: boolean = false; private leftTime: number = 0; constructor() { super(); this.timerClient = new TimerClient('http://' + window.location.hostname + ':8081', null, null); } private startTimer(): void { const request = new StartRequest(); request.setTime(10); // 10秒をセット const stream: ClientReadableStream<TimerState> = this.timerClient.startTimer(request, {}); stream.on('data', (response: TimerState) => { this.isTimerRunning = response.getIsrunning(); this.leftTime = response.getLefttime(); }); } private stopTimer(): void { this.timerClient.stopTimer(new Empty(), {}, (err, response: TimerState) => { this.isTimerRunning = response.getIsrunning(); this.leftTime = response.getLefttime(); }); } } </script> <style lang="scss"> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } .time{ margin:0 0 40px 0; font-size:148px; color:#999; } </style>Typescript側は、コンストラクタでAPIクライアントをインスタンス化し、開始ボタン or 停止ボタンで対応するAPIをコールします。
タイマー開始の方はサーバー側から時間が変わるたびにデータがプッシュされてくるので、その値に応じて秒数を更新する仕組みです。プロキシサーバーを用意
ここに関しては公式のサンプル通りです。
正直よくわかってないです。
envoyというプロキシサーバー(本来はロードバランサらしい?)を使います。
現状gRPCのリクエストをダイレクトにサーバーに伝えられないらしいです。(なぜだ。ポートの問題?)公式のチュートリアルから、
envoy.Dockerfile
envoy.yaml
をひろってきて、以下のコマンドでdocker build -t envoy_for_timer -f ./envoy.Dockerfile .実行する
サーバーアプリ起動
python TimerApi.pyリバースプロキシ起動
docker run -d -p 8081:8081 envoy_for_timerフロントアプリ起動
yarn serveフロントアプリを起動後に
App running at: - Local: http://localhost:8080/ - Network: http://192.168.1.22:8080/と表示されましたら、上記アドレスでアクセスできるはずです。
感想
- REST APIしか触ったことない勢としては、サーバーからのプッシュ型のAPIは触ってて面白かったです。
- streamでつなぎ続けると再度実行されたときに前のものをキャンセルしたりしたいケースもありそうだなと思いました。
- Python版は情報が少ない。DBとのつなぎをDjangoにすることをもくろんでPythonを選んだけれど、Goで書いた方がよいのかなと悩む。
- Typescriptの方はmessageの変数名の補完が効いた。Pythonの方はほとんど効かなかった。Pythonだめなのかなー。。
こちらからは以上です。