- 投稿日:2020-08-30T23:50:13+09:00
Dockerの備忘録
Dockerデーモン
コンテナを管理する永続的なプロセスでありDocker デーモンはユーザーからのDockerコマンドによる命令を実行することでコンテナの起動や再起動、停止などの管理をしている。
Docker Hub
Dockerイメージのレジストリサービス。
Dockerイメージの公開、検索、ダウンロードすることができる。Dockerイメージ
コンテナ実行に必要なファイルをまとめたファイルシステム。
AUSFなどの特殊なファイルシステムが使用されている。
イメージ上のデータはレイヤで構成され読み取り専用。イメージの一覧表示
% docker images新しいイメージを作るコマンド
## % docker tag 元のイメージ名 新しいイメージ名 % docker tag docker/whalesay my_whalesay ## % docker tag 元のイメージ名 新しいイメージ名:タグ % docker tag docker/whalesay my_whalesay:num1下の場合は「num1」と言うタグ名がつけられた「my_whalesay」というイメージが作られる。
イメージの詳細情報を表示するコマンド
## % docker inspect 対象のイメージ若しくはイメージID % docker inspect my_whalesay
イメージを削除するコマンド
## % docker rmi 対象のイメージ若しくはイメージID % docker rmi docker/whalesay
イメージを強制削除するコマンド
## docker rmi -f 対象のイメージ若しくはイメージID % docker rmi -f docker/whalesay
イメージを取得するコマンド
## % docker pull 取得したいイメージ % docker pull docker/whalesay
latestが新しいイメージでは無い可能性もあるので詳しくは公式参照。
Dockerfile
イメージの定義ファイル。Dockerfileからイメージをビルドすることをイメージビルドという。
## FROMはイメージを作る際、元のイメージを指定する今回はdocker/whalesay:latest FROM docker/whalesay:latest ## RUMはイメージビルドの際にコマンドを指定する RUN apt-get -y update && apt-get install -y fortunes ## CMDはコンテナが作成された後で実行するコマンドを指定する命令 CMD /usr/games/fortune | cowsayDockerfileからイメージをビルドするコマンド
## % docker build -t イメージ名 . % docker build -t docker-whale .
-tはビルドしたイメージに名前をつける今回はdocker-whale。
「.」はビルドコンテキストの設定でイメージを作成する際にアクセスできるディレクトリや、ファイルの範囲を示すもの。今回はカレントディレクトリを示す.(ピリオド)。## % docker build --no-cache -t イメージ名 . % docker build --no-cache -t docker-whale .
上記は再度Dockerfileでイメージビルドする際、キャッシュが適用され更新されず、
新しいパッケージがインストールされないのを防ぐコマンド。
キャッシュが使わずに更新することができる。DockerHubにログインする
% docker login Username DockerHubのユーザー名 Password: DockerHubのパスワード成功したら「Login Succeeded」と表示される。
DockerHubにおけるタグ付けルール
## % docker tag 元のイメージ名 リポジトリ名:タグ名 % docker tag docker-whale user/docker-whale:num1
DockerHubの「user/docker-whale」というリポジトリにpushするのでこのような記述になる。
タグ名を指定しない場合はlatestタグになる。
リポジトリ名を間違えるとpushできないので注意!DockerHubにイメージをpushする
## % docker push リポジトリ名:タグ名 % docker push user/docker-whale:num1
ここでエラーが出た場合、再度リポジトリ名が合っているか確認する。
DockerHubのリポジトリにイメージがpushできていることを確認する。DockerHubからイメージをpullする
## % docker pull イメージ名:タグ名 % docker pull user/docker-whale:num1
docker imagesコマンドでイメージがpullできていることを確認する。
nginxのコンテナを立ち上げるコマンド
## % docker run --name コンテナ名 -d -p ホスト側ポート番号:コンテナのポート番号 イメージ名 % docker run --name some-nginx -d -p 8080:80 some-content-nginx
--neme は起動するコンテナに名前をつけるオプション。
-d はデタッチモードでコンテナの実行をバックグラウンドで行うもの。入力が無い場合、実行した画面で他の操作ができなくなるため、入力することを推奨。
-p はコンテナのポートをコンテナ外に設定するオプション。ここでは8080が外部に公開するポート番号。
正常に実行された場合、http://localhost:8080/ でnginxが起動していることが確認できる。
- 投稿日:2020-08-30T20:05:02+09:00
Windows Containerを使ってみて、独自イメージビルド時の注意点
この記事は富士通システムズウェブテクノロジーの社内技術コミュニティで、「イノベーション推進コミュニティ」
略して「いのべこ」が企画する、いのべこ夏休みアドベントカレンダー 2020の12日目の記事です。
本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません。
ここまでお約束Windows Containerとは
Windows ContainerとはWindows10またはWindows Server(2016以降)で利用できる、
Windwosベースのコンテナのことです。docker runでWindowsが動き出すのはちょっと感動です。もちろん、Windows環境でしか利用できませんが・・・
本記事では、Windwos ServerでWindows Containerの機能をインストールし、起動~Dockerfileによる独自イメージの作成を行った際に、ハマったこと・Windows ContainerならではのDockerfileの書き方の工夫を書き残します。
Windows Containerを使用するための環境の容易には、以下のサイトを参考にしています
https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/quick-start/set-up-environment?tabs=Windows-Server環境
- Windows Server 2019 Standard 1809 (ビルド番号:17763.1397)
基本イメージ
Windows Containerには、いくつかの基本イメージがあります。
https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/manage-containers/container-base-imagesイメージごとに、インストールされているコンポーネントが異なり、サイズもそれに応じて異なります。
基本イメージ名 サイズ mcr.microsoft.com/windows 4.2G mcr.microsoft.com/windows/servercore 3.7G mcr.microsoft.com/windows/nanoserver 251M mcr.microsoft.com/windows/iotcore 307M ※すべてタグは「10.0.17763.1217-amd64」を指定しています。
タグについて
ホストしているWindows Serverのビルド番号(今回の例だと、17763.1397)と、コンテナのタグのビルド番号(10.0.{ビルド番号}-xxxx-amd64の部分)が異なると、コンテナは起動しません。
例えば
ホストのビルド番号が14393.*で、コンテナのビルド番号が17763.1217の場合、コンテナの起動はブロックされます。
私の環境だと、そもそもpullするときに指定したタグ名: Pulling from windows no matching manifest for windows/amd64 10.0.17763 in the manifest list entries
というエラーが出て、pullできなかったですこれは、Windows Containerと、ホストしているサーバのカーネルは共有されるためです。
公式ページの説明によると、「起動するかもしれませんが・・・」と書かれておりますが、起動させることすらできませんでした。
https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2004%2Cwindows-10-2004#windows-server-containers
Windows Updateにより、ホストしているサーバのビルド番号に変更があった場合には、コンテナも再ビルドが必要になると覚えておいたほうがよさそうです。ベースイメージの使い分け
各種ベースイメージには、インストールされているコンポーネントが異なり、公式ページでは以下のように案内されています。
https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/manage-containers/container-base-images#guidelines
- アプリケーションに完全な .NET フレームワークは必要ですか。
- この質問への答えが「はい」の場合、Windows Server Core をターゲットにすることをお勧めします。
- .NET Core に基づいて Windows アプリを構築していますか。
- この質問への答えが「はい」の場合、Nanoserver をターゲットにすることをお勧めします。
- IoT アプリケーションを構築していますか。
- この質問への答えが「はい」の場合、IoT Core をターゲットにすることをお勧めします。
- アプリに必要な依存関係が、Windows Server Core コンテナー イメージに不足していますか。
- この質問への答えが「はい」の場合、Windows をターゲットにしてみることをお勧めします。 このイメージは、他の基本イメージよりもサイズがはるかに大きく、多数のコア Windows ライブラリ (GDI ライブラリなど) が含まれています。
こんな感じのイメージでしょうか。
そのほかにも、NanoserverにはPowerShellがインストールされていないなどの相違点があるようでした。
docker run 実行時の注意点(Volume指定時)
volume指定時、マウント先を
D:\
などに指定しようとするとエラーになります。
C:\
以下にマウントされるようにdocker run xxxx -v ${pwd}:C:\share xxxx
と指定してあげる必要があります。Dockerfileの書き方
Dockerfileの書き方について、詰まったことを書き記しておきます。
パッケージマネージャーが弱い
基本的に、Windowsにはyum/aptのような高性能なパッケージマネージャーがありません
PackageManagementという機能があるので、それを使えば必要そうなのはある程度取れそう・・・?
ProviderもChocolateyとかを選べるので、あとはリポジトリの中に欲しいのを探してみてください。wingetもWindows Serverでも使えるようになったりするかしら?
RUNコマンドの形式
RUNコマンドは、cmd.exeに対して実行されるようで、cmd.exeで実行してうまく動かないようなコマンドは失敗します(悲しいかな・・・)
Linuxコンテナの場合、以下のように書いたりすると思います
FROM alpine:latest # パッケージマネージャでいろいろインストールして、そのあと本当に必要なコンポーネントをインストールする。みたいな RUN apk update \ && apk add --no-cache curl\ && curl -L "https://golang.org/dl/go1.15.linux-amd64.tar.gz" -o /tmp/go1.15.linux-amd64.tar.gz \ && mkdir /go && tar /tmp/go1.15.linux-amd64.tar.gz -C /go && apk del curl \ && rm -f /tmp/go1.15.linux-amd64.tar.gzイメージサイズを縮小するためにこのようにするかと思いますが、当然Windowsですがコマンドが変わってきます。
コマンドプロンプトでやるように、
&
で区切ってコマンドを記述していきます。Windows版RUN powershell.exe Invoke-WebRequest -Uri "https://golang.org/dl/go1.15.windows-amd64.zip" -Outfile ".\go1.15.windows-amd64.zip" \ & mkdir C:\go \ & powershell.exe Expand-Archive .\go1.15.windows-amd64.zip -DestinationPath C:\go \ & del .\go1.15.windows-amd64.zippowershell内のコマンドをたたくとき、いちいち
powershell
を指定しないといけないので少し面倒です。
1行で実行したいときには、powershell化したりすることを検討したほうがいいかなと思ってます。ADDコマンドについて
RUNコマンドなどの場合は、cmd.exeで実行しているので¥区切りでコマンドを記述する必要がありますが、ADDコマンドは/区切りでパスを記述しないとエラーになります。。。ドウシテ
おそらく、Dockerfile側の都合なので、仕方ないのかなと思います。例えば、こんなDockerfileを書いたとします。
Windows版FROM mcr.microsoft.com/windows/servercore:10.0.17763.1217-amd64 RUN mkdir C:\app ADD test.exe C:\appこれでビルドをかけると、
Sending build context to Docker daemon 2.56kB Step 1/3 : FROM mcr.microsoft.com/windows/servercore:10.0.17763.1217-amd64 ---> 503b39abeba7 Step 2/3 : RUN mkdir C:\app ---> Using cache ---> e2b88aa43ff5 Step 3/3 : ADD test.exe C:\app failed to copy files: failed to copy file: mkdir \\?\Volume{7d8c5343-b2a5-499b-add3-7f392ece5972}\C:.: The directory name is invalid.こんな感じのログで異常終了します。なので、かならず以下のようにしましょう
Windows版FROM mcr.microsoft.com/windows/servercore:10.0.17763.1217-amd64 RUN mkdir C:\app ADD test.exe C:/app # ADDの時は/区切り!覚える!追加ソフトウェアのインストール時
Package Managerに目当てのソフトウェアがない場合、exeやmsiをダウンロードしてきて、ビルド時に実行する必要があります。
その際、以下のようにすることでコマンドラインからsilentインストールができます。※基本的には、下記の記事の受け売りです
https://qiita.com/lanevok/items/270c4ee73dba1d77e1f9msi形式の場合
C:\ msiexec /i インストール対象.msi /passive /norestartexeの場合
C:\ インストール対象.exe /s /v"/qn REBOOT=ReallySuppress ADDLOCAL=ALL"上記の方法でうまくいかないものは、個別のオプションがあったりするので、インストールしたいコンポーネントごとにオプションを変えたりしてみてください。
感想
触ってみて、起動が若干遅い(ウィルススキャンソフトとかの影響らしいです。Windows Defenderだけでも結構遅い・・・)し、
パッケージ系のインストールがどうしても難ありな感じしかなくて、たぶん検証用途だったり、
開発環境用のサーバ構築用途ぐらいにしか使わないなぁと・・・
もう少しフットプリントが軽くなったりエコシステムが出そろってくると、メリットも出てくるのかもしれませんが。とはいえ、コンテナ起動時のメモリ使用量も、windowsベースコンテナで起動直後に80MB前後、
dockerdも30MB程度しかメモリを消費していないところを見ると、VMをポコポコ立ち上げるよりはよっぽど軽量です。これを機に、Windows Server系の資産をコンテナに置き換えられたらいいなと思う今日この頃でした。
それにしても、Windows Containerなのか、Windows Server Containerなのか。どっちなんでしょう。
Windows Serverで動かしたらWindows Server Containerになるとかそういうあれですかね?
- 投稿日:2020-08-30T19:53:58+09:00
最近(2020/08)のDocker for Macのファイルアクセス遅い問題事情メモ
調べたことまとめる。
- いにしえよりDocker for Macでhost-container間のファイルアクセス遅い問題は議論されている
- macOSでなんで遅いかが↓ここら辺に書いてあるっぽい(が読んでない
- その問題の対応として、2017年にvolumesオプションに
cached
,delegated
フラグが追加された。consistencyを少し犠牲にしてファイルアクセスを高速化している。consistent
(デフォルト) >cached
>delegated
の順にconsistencyが高い。- 以下のベンチマークだと、consistent(デフォルト)と比べて
cached
,delegated
は2-3倍くらい速い。- が、これでもまだLinuxなどに比べると遅く、公式じゃない手段でいくつかそれより高速化する方法がある。
- https://www.jeffgeerling.com/blog/2020/revisiting-docker-macs-performance-nfs-volumes
- ここでいろいろ手動で設定してNFSマウントする方法、 docker-sync と言うgem、 bg-syncと言うcontainerがベンチマークとともに紹介されている。いずれも
delegated
flagより2倍かそれ以上速い。- 一方Docker公式ではMutagenと言うツール(?)がEdgeリリース v2.3.1.0(2020-05-20)で導入された。ネイティブに近いパフォーマンスが出るらしい。
- しかし、これがパフォーマンス改善に効果がある一方、いくつか問題がありEdge v2.3.5.0で削除された
- https://docs.docker.com/docker-for-mac/edge-release-notes/#docker-desktop-community-2350
- ↓で理由が説明されている。キャッシュが追いつかない場合があったり、サブディレクトリがキャッシュされない問題があったりするらしい(詳しく知らないので読み間違えてるかも)
- 代わりにgRPC-FUSEと言うファイルシステムが同じEdge v2.3.5.0で導入された。
- 公式曰く "This has much faster file sharing and uses much less CPU than osxfs" らしい(osxfsが古い(現状の)ファイルシステム)が、上記issueにポストされたベンチマークでは全然速くなってなかった。
- 上記issueにMutagenの開発者が、「Docker for Mac導入されなくてもMutagen自体は使えるから試してみてね」的なこと言ってる。
- mutagenが削除されることを不満に思っている人が多いようで「mutagen入ってるEdge release build使い続けるわ」とか同issueにコメントついてる。
- mutagenはEdgeの時点で削除され、stableに入る予定は今のところない(が、いろいろ考え直してデザインし直して入り直す可能性はある)。gRPC-FUSEは9月にstableに入る予定。デフォルトでgRPC-FUSEになるが、設定で古いやつ(osxfs)に切り替えることができる。
- 投稿日:2020-08-30T18:31:45+09:00
WSL2を使ったDokcerで、`Aws::S3::Errors::RequestTimeTooSkewed` のエラー対処法
環境
- WSL2 (Windows 10 Home)
- Docker for Windows
エラー
Docker上で、AWSと連携しようとしたときに、
Aws::S3::Errors::RequestTimeTooSkewed: The difference between the request time and the current time is too large.のエラーが出た
原因
WSL2で動くDockerコンテナの時刻が大幅にずれているのが原因
Windows ホスト側
$ data Sun Aug 30 18:16:29 JST 2020コンテナのシェル内
$ data Sun Aug 28 11:16:29 JST 2020解決法
はじめに
Aws::S3::Errors::RequestTimeTooSkewed
のエラーはTimezoneが違う場合でも発生するので、
docker-compose.yml 内でtimezone をJSTに設定しとく。docker-compose.ymlservices: web: environment: TZ: Asia/Tokyoつぎに
WSL2の時刻を
data --set
コマンドで同期させる。
まず、コンテナのシェル内でdataコマンドを使うときに、operation not permitted
にならないように、権限設定をしとく必要がある。docker-compose.ymlservices: web: privileged: trueつぎに
コンテナのシェル内で、
data
コマンドを使って日付を変更する$ data --set "2020-08-30 18:16:29"で完了。
他に試したこと
hwclock -s
を用いて無理やり時間を変えれるらしい。-> 下記のエラーが出て、少し解決しようとしてみたが、謎すぎて諦めた
$ hwclock -s hwclock: Cannot access the Hardware Clock via any known method. hwclock: Use the --debug option to see the details of our search for an access method参考リンク
- 投稿日:2020-08-30T15:25:39+09:00
WEB爆速の貴公子を目指して Lighthouse-ciを動かしてみる
はじめに
速さが足りない!!
という訳で、サイトの速度を改善していくために計測が必要ですよね?
定期的に計測する方法を探しているときに Lighthouse-ciを見つけました。
その中でも計測結果をダッシュボードで可視化させチームでの速度改善に取り組むために
LHCI Serverについて話していこうと思います。
どんなものかをざっくりと公式の画像つきで紹介します。
LHCI Server を用意するために必要なもの
- Node v10 LTS以降
- データベースストレージ(sqlite、mysql、またはpostgresql)
公式の参考画像
できること
- Lighthouseの計測結果を記録することができる
- コミット単位で計測結果を見ることができる
- 今までの計測結果をグラフとして可視化することができる
- ローカル環境や本番URLどちらも計測することができる
- 計測ごとの詳細の差分を可視化することができる
とりあえず公式をみながら手を動かしていった方がイメージつきやすいと思うのでやってみましょう。
やることリスト
- 公式をみながらLHCI Serverを準備する
- herokuでやってみよう
- dockerでやってみよう
- LHCI Serverに計測するプロジェクトを登録
- 計測のための設定ファイルを書く
- GithubActionsでpush時に計測してみる
LHCI Serverを準備する
公式のREADMEの方にherokuとdockerでさくっと立ち上げる方法が書いてあるのでやってみましょう
下準備として下記が使えるようになってますでしょうか?参考記事と公式のドキュメントを添付しておきます。
- heroku CLI
- docker
参考
どちらもデプロイするものは同じなので好きな方を選んでもらえればいいと思います。
herokuでやってみる
こちらを利用する場合まずherokuにアカウントを登録しましょう
Heroku はアプリの構築、提供、監視、スケールに役立つクラウドプラットフォームで、アイデアを出してから運用を開始するまでのプロセスを迅速に進めることが可能です。また、インフラストラクチャの管理の問題からも解放されます。
公式から引用(https://jp.heroku.com/what#summary)herokuを使えばいろんな言語でさくっとデプロイできますね。Rails チュートリアルでも利用されてるやつですね。
利用できるやつの例
言語
- Node
- Ruby
- Python
- Java
- PHP
- Go
- Scala
- Clojure
データベース
- Redis
- PostgreSQL
早速手を動かしましょう!
公式のREADMEの内容を触っていこうと思います。
- リポジトリを準備します。
# 作業ディレクトリとリポジトリの準備 mkdir lhci-heroku && cd lhci-heroku && git init # LHCI Serverに必要なファイルを取ってきます。 curl https://raw.githubusercontent.com/GoogleChrome/lighthouse-ci/master/docs/recipes/heroku-server/package.json > package.json curl https://raw.githubusercontent.com/GoogleChrome/lighthouse-ci/master/docs/recipes/heroku-server/server.js > server.js # コミット git add -A && git commit -m 'Initial commit'ダウンロードしてくるファイルは下記のような内容になります。
package.json{ "name": "lhci", "version": "1.0.0", "main": "server.js", "dependencies": { "@lhci/server": "0.4.x", "pg": "^7.12.1", "pg-hstore": "^2.3.3" } }server.js/** * @license Copyright 2019 Google Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ 'use strict'; const {createServer} = require('@lhci/server'); console.log('Starting server...'); createServer({ port: process.env.PORT, storage: { storageMethod: 'sql', sqlDialect: 'postgres', sqlConnectionSsl: true, sqlConnectionUrl: process.env.DATABASE_URL, }, }).then(({port}) => console.log('Listening on port', port));sqlDialect でデータベースの種類と sqlConnectionUrlでデータベースのURLを指定していますね。
LHCI Serverではデータベースの接続としてURLを利用します。
postgres://{ユーザー名}:{パスワード}@{ホスト名}:{ポート番号}/{DB名}さて早速herokuにデプロイしてみましょう!!
heroku CLIをここから使用していきます。
# heroku上に新しいプロジェクトを作成します。 heroku create # プロジェクトでpostgresqlを使えるようにします。 heroku addons:create heroku-postgresql:hobby-dev # herokuにデプロイしてみます。 git push heroku master # 実行確認し、デプロイされたアプリを開きます。 heroku ps:scale web=1 heroku openこのような画面が確認できればOKです。
なんか lhci wizard とか書いてますね、このコマンドは LHCI Serverに計測したいプロジェクトを登録するのに必要なコマンドになります。
早速herokuの lhci serverにプロジェクトを登録したい方はこちら
dockerでやってみる
dockerとはさくらナレッジさんの記事が個人的にわかりやすいので添付しておきます。
Dockerは、インフラ関係やDevOps界隈で注目されている技術の一つで、Docker社が開発している、コンテナ型の仮想環境を作成、配布、実行するためのプラットフォームです。
引用元: Docker入門(第一回)~Dockerとは何か、何が良いのか~docker でLHCI Serverを動かしてみましょう。
こちらも公式のREADMEの内容を触っていこうと思います。Docker Hubにimageが上がっているので使っていきます。
patrickhulce/lhci-server
https://hub.docker.com/r/patrickhulce/lhci-server
今回は docker-compose.ymlを利用する方法で準備していきましょう
mkdir lhci-docker && cd lhci-docker && touch docker-compose.ymldocker-compose.ymlversion: '3' services: lhserver: image: patrickhulce/lhci-server ports: - '9001:9001' volumes: - lhci-data:/data volumes: lhci-data:
patrickhulce/lhci-server
はデフォルトだとsqliteを利用しているので データ保存先の/data を永続化しています。
patrickhulce/lhci-server
中をみてみましょうlighthouserc.json{ "ci": { "server": { "port": 9001, "storage": { "storageMethod": "sql", "sqlDialect": "sqlite", "sqlDatabasePath": "/data/lhci.db" } } } }sqlDialect で sqlite
sqlDatabasePathで sqliteの保存先が書いてあります。登録先をheroku同様postgresなどに変更することもできます。
ローカル環境で起動してみる
docker-compose up -d
http://localhost:9001/
こちらにアクセスこのような画面になればOKです。
なんか lhci wizard とか書いてますね、このコマンドは LHCI Serverに計測したいプロジェクトを登録するのに必要なコマンドになります。
計測結果を記録してみる
lhci serverで先ほどからデプロイ完了した後に出てくる、lhci wizardこちらのコマンドを使用してプロジェクトの登録からlhci autorunというコマンドを利用してプロジェクトを計測しlhci serverに計測結果を登録しましょう。
プロジェクトのLHCI Serverへの登録
登録したいプロジェクトのディレクトリで作業していきましょう
# lhci serverのバージョンを確認する curl https://{lhci serverのURL}/version # Make sure you can connect to your server. 0.x.x僕の場合は
0.44
と返ってきました# 取得したバージョンに対応した物をインストールします。 # 僕の場合だと0.44が返ってきたので... npm install -g @lhci/cli@0.4.4# lhci wizardコマンドを使用 lhci wizard # 何個か質問がきます。 # lhci serverに新規でプロジェクトを登録します ? Which wizard do you want to run? new-project # lhci serverのURLを登録 ? What is the URL of your LHCI server? https://your-lhci-server.example.com/ # lhci serverに登録するプロジェクト名を登録 ? What would you like to name the project? My Favorite Project # プロジェクトのコードが管理されている場所 自分のソースがあるリポジトリのUR ? Where is the project's code hosted? https://github.com/GoogleChrome/lighthouse-ci # 対象のブランチ名 ? What branch is considered the repo's trunk or main branch? masterこれらのコマンドを実行し終わると
- build token
- admin token
が出てきますのでメモしておきましょう
Created project My Favorite Project (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)! Use build token XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX to connect. Use admin token XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX to manage the project.この時点で確認してみると 今回僕は testという名前でプロジェクトを登録しました。
しかしこの状態ではサイトの計測は行われていないので計測していこうと思います。プロジェクトの計測
計測のために必要な
lighthouserc.js
というファイルを書いていきましょうlighthouserc.jsmodule.exports = { ci: { upload: { target: 'lhci', serverBaseUrl: 'https://your-lhci-server-url.example.com', token: 'Your *build token* goes here', // could also use LHCI_TOKEN variable instead }, }, };今回は lhci serverに計測結果を記録するので
target
はlhci
serverBaseUrl
ここで登録したURLを記載? What is the URL of your LHCI server? https://your-lhci-server.example.com/
token
はここのtokenを記載
Use build token XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX to connect.この状態ではどこのURLを計測すればいいのか記載されていないため追記してみましょう
静的サイトを対象に計測する時
lighthouserc.jsmodule.exports = { ci: { collect: { staticDistDir: './dist', url: ['/'], }, upload: { target: 'lhci', serverBaseUrl: 'https://your-lhci-server-url.example.com', token: 'Your *build token* goes here', // could also use LHCI_TOKEN variable instead }, }, };
staticDistDir
に静的ファイルがある場所を選択します。
url
に計測したいURLを記載します。静的なサイトではない場合
lighthouserc.jsmodule.exports = { ci: { collect: { startServerCommand: 'rails server -e production', url: ['http://localhost:3000/'], }, upload: { target: 'lhci', serverBaseUrl: 'https://your-lhci-server-url.example.com', token: 'Your *build token* goes here', // could also use LHCI_TOKEN variable instead }, }, };
startServerCommand
にサーバーの起動のコマンドを入れてあげます 上記は railsの例です。
url
に計測したいURLを記載します。指定したURLで計測
本番のURLとか実在するサイトに対して行う場合は、startServerCommandは必要ないため
URL指定だけでも計測可能です。lighthouserc.jsmodule.exports = { ci: { collect: { url: ['URL'] }, upload: { target: 'lhci', serverBaseUrl: 'https://your-lhci-server-url.example.com', token: 'Your *build token* goes here', // could also use LHCI_TOKEN variable instead }, }, };計測
# 計測 lhci autorun
デフォルトだと計測回数は3回計測されます。
計測回数を変えたい時は、
lighthouserc.jscollect: { numberOfRuns: 1, },
numberOfRuns
に回数を指定すれば問題ないです当たり前ですが計測回数を増やせばそれだけ計測にかかる時間は増えます
Github Actionsで計測する
GithubActionsとは
プッシュ、Issue、リリースなどのGitHubプラットフォームのイベントをトリガーとしてワークフローを起動しましょう。コミュニティが開発・保守し、ユーザが熟知・愛用しているサービスについて、対応するアクションを組み合わせて設定できます。
引用元: https://github.co.jp/features/actionsこれを利用すれば好きなタイミングで自動的に計測を行ってくれますね。
今回はリポジトリpush時に作動する簡単なciファイルが、Lighthouse-ciの公式に書いてあるのでそちらを利用していきます。
https://github.com/GoogleChrome/lighthouse-ci
github/workflows/ci.ymlname: CI on: [push] jobs: lighthouseci: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 - run: npm install && npm install -g @lhci/cli@0.4.4 - run: npm run export - run: lhci autorun僕の場合は サンプルから
変更しています。
いざpush!!
無事CI実行できましたね
まとめ
- Lighthouseの計測結果を記録することができる
- コミット単位で計測結果を見ることができる
- 今までの計測結果をグラフとして可視化することができる
- ローカル環境や本番URLどちらも計測することができる
- 計測ごとの詳細の差分を可視化することができる
他にもassertを設定したり。
Basic認証を設定したりできるので色々試してみてください。
- push 時のタイミングで計測し一定を下回ったら失敗するようにしてみたり
- スケジューリングで毎日一定時間に本番のURLを計測してみたり
などいろんな使い方があるのかと思います。
また記録が保存されているデータベースの中身をみに行くと面白いです。
僕自身も使い始めたばかりなので知っている方色々教えてくださると助かります。
長い間お付き合いいただき,ありがとうございました。
いざ!WEB爆速の貴公子へと
- 投稿日:2020-08-30T13:13:17+09:00
Intel入ってるNASでVAAPIを使う
きっかけ
nasneでTVを観ているのですが,
- 視聴に専用のソフトが必要
- Macで視聴するには,
- Parallels/VMware Fusionなどのような,高性能な仮想化ソフトウェアを用いてPCTV Plusで視聴しないといけない.
- 非公式なMac用ソフトウェアが必要.
- そもそもnasneのHDDが死んだときに録画データも死ぬ.当然市販のレコーダーだって同様.
- 市販の録画機では冗長性0.
などの問題があり,市販のエンドユーザ向け録画機ではまともに利用できません.
そこで,録画サーバを構築しようと思ったのですが,サーバでトランスコード/エンコードができないと,
帯域・ストレージリソースを大量に消費してしまいますよね.
そうなると,HWエンコーダなどの支援がほしいところです.NAS
現在,私はSynology DS218+というNASを持っています.
このNASは,IntelのCeleron J3355というCPUが内蔵されています.このため,Synology公式でDockerに対応しています.
また,このCPU,Intel公式を見てみると,QSVに対応している模様です.
https://ark.intel.com/content/www/jp/ja/ark/products/95597/intel-celeron-processor-j3355-2m-cache-up-to-2-5-ghz.html
つまり,DockerからうまいことHWエンコーダを呼び出せば,QSVを利用して高速エンコードができるようになります.目的
しかし,やはり実際にエンコードを走らせてみないと,まともに使えるのかわかりません.
そこで,本記事においての目的としては,録画サーバを組む前段階として,
Intel入ってるNASでは,HWエンコードがどのくらいの性能なのか?とします.用意したもの
DS218+
- おそらくQSV対応のIntel CPUを積んでいて,以下の条件に合致していれば,他のNASでも使えると思います.
- NASにSSH可能
- Dockerインストール済み
- 後述するスクリプト
- DSMのLinuxカーネル4.4.59+
$ uname -r 4.4.59+30分アニメを録画したtsファイル(hoge.ts)
非公式なので,何があっても自分でなんとかする強い気持ち
検証
IntelCPUが入っている本NASにおいては,encordデバイスが
/dev/dri:/dev/dri
にあります.
他のIntelCPUが内蔵されているものも同様かと思われます.
これをコンテナに渡してやることで,コンテナ内にて,ホストのHWエンコーダを利用できます.方法
こちらを参考にしました.→https://timothybasanov.com/2018/12/08/hardware-accelerated-h264-encoding-synology-nas.html
今回は,VAAPIでQSVを使います.
このため,VAAPIに対応したffmpegなDockerコンテナで検証します.以下のスクリプトを書きました.
encord_test.sh#!/bin/sh host_tsdir=/volume1/video container_tsdir=/tmp host_mp4dir=/volume1/video/mp4 container_mp4dir=/media movie_name=hoge sudo docker run --rm \ --device /dev/dri:/dev/dri \ -v ${host_tsdir}:${container_tsdir} \ -v ${host_mp4dir}:${container_mp4dir} \ jrottenberg/ffmpeg:vaapi \ -hwaccel vaapi -hwaccel_output_format vaapi \ -i ${container_tsdir}/${movie_name}.ts \ -vf 'scale_vaapi=w=1280:h=720' \ -c:v h264_vaapi \ ${container_mp4dir}/${movie_name}.mp4結果
エンコード速度とCPU負荷の検証,エンコード前後でのファイルサイズの比較を行いました.
実行速度
まず,スクリプトを実行したときの実行結果です.
4倍以上,安定してエンコードできているのがわかります.非常に高速です../encord_test.sh (省略) Output #0, mp4, to '/media/hoge.mp4': Metadata: encoder : Lavf58.20.100 Stream #0:0: Video: h264 (h264_vaapi) (avc1 / 0x31637661), vaapi_vld, 1280x720 [SAR 1:1 DAR 16:9], q=-1--1, 29.97 fps, 30k tbn, 29.97 tbc Metadata: encoder : Lavc58.35.100 h264_vaapi Stream #0:1: Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s Metadata: encoder : Lavc58.35.100 aac frame= 1996 fps=142 q=-0.0 size= 42240kB time=00:01:06.46 bitrate=5206.1kbits/s dup=14 drop=0 speed=4.72x処理負荷
このとき,どのくらいのCPUリソースを利用しているのかみてみました.
ちなみにリソース監視は,Prometheus+NetData+GrafanaをDockerで建てて,フルコンテナ運用しています.
スクリーンショットはGrafanaのダッシュボードです.
概ね40%ちょっとくらいのCPU使用率で安定しています.
圧縮率
今回,1920x1080のtsファイルを,1280x720のmp4(h264)に変換したため,割と小さいサイズになっています.
概ね半分以下のサイズに抑えられています.
まとめ
非常に実用的な速度で,実用的なリソース消費で,消費電力も(おそらく)そこまでではなさそうなので,
IntelのQSVが使えるNASをお持ちであれば,エンコードサーバにするのもありだと思います.
今回,録画サーバにおけるエンコード性能として検証しましたが,systemdで適当に動かすなり,
cronでスケジューリングなりすれば,NASに溜めておいたホームビデオの自動エンコードなども可能になると思います.
また,まだまだffmpegの設定を調整すれば,さらなる容量削減や,インターレース解除などもできると思いますし,
そこあたりは今後の課題とします.いいffmpegオプションなどありましたらぜひ教えて下さい.録画サーバを組むとしたら
チューナデバイスとしては,PX-S1UDを考えています.このチューナ,ドライバがPLEX公式から出ています.
また,Linuxのディストリ依存などがなく,DSMでも動く模様(https://qiita.com/xingoxu/items/c813c4ed048116f653a6#%E3%82%A2%E3%83%B3%E3%83%86%E3%83%8A%E8%A8%AD%E7%BD%AE )です.良かった.
当初は,エンコード性能・省電力性能が高いRaspberry Pi4を買おうか迷っていましたが,NAS一台で完結しそうです.
また,録画サーバのソフトウェア周りも実はコンテナ化して運用可能です.
https://github.com/l3tnun/docker-mirakurun-epgstation
つまるところ,NAS一台で,録画サーバまでフルコンテナ運用ができそうです.
万一,Docker内サーバの環境が壊れても,別にいくつかのバックアップをちゃんと取るようにしているので,
ある程度の冗長性が確保できそうです.かなり安定性の高い録画システムが組めるのではないでしょうか.おまけ
1920x1080で出力した結果がほしいという声が聞こえてきそうなので,検証してみました.
実行速度
Output #0, mp4, to '/media/hoge.mp4': Metadata: encoder : Lavf58.20.100 Stream #0:0: Video: h264 (h264_vaapi) (avc1 / 0x31637661), vaapi_vld, 1920x1080 [SAR 1:1 DAR 16:9], q=-1--1, 29.97 fps, 30k tbn, 29.97 tbc Metadata: encoder : Lavc58.35.100 h264_vaapi Stream #0:1: Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s Metadata: encoder : Lavc58.35.100 aac frame=52707 fps= 85 q=-0.0 Lsize= 2034563kB time=00:29:18.59 bitrate=9477.6kbits/s dup=14 drop=0 speed=2.85x処理負荷
ダウンコンバートしていないためか,多少,CPU負荷が少なくなっています.概ね40%行かないくらいのCPU使用率ですね.
圧縮率
- 投稿日:2020-08-30T12:04:42+09:00
alpine-linuxでcode-serverを立ち上げる
Alpine-Linux上でcode-serverを立ち上げる
Pythonの開発環境を構築する必要があり調査を実施。
以下のDockerfileで起動し、それとなく使える事が判明した。
ベースイメージはpythonオフィシャルの3.7-alpineを使用したが、通常のalpine-linuxでも起動できると思う。FROM python:3.7-alpine RUN apk --no-cache --update add alpine-sdk bash libstdc++ libc6-compat npm libx11-dev libxkbfile-dev libsecret-dev && \ npm config set unsafe-perm true && \ npm install -g code-server ENTRYPOINT ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080"] CMD [""]注意事項
- ポート番号は8080なので、docker起動時にポートのマッピングが必要
- 鍵情報を作らないとブラウザ等からクリップボード等のアクセスに問題がある模様?insecureだと警告がでる。
- スリム化は行っていない。現状、docker images上で944MBと表示される。
- 認証も外しているので、インターネット等外部からアクセスするようなところでの起動は自己責任で。
- その他、使い込んでいないので、他にどのような問題があるかは不明。
- 投稿日:2020-08-30T11:54:36+09:00
Amazon ECRがOCI ArtifactをサポートしてHelm chartsも管理できるようになったよ
はじめに
2020/8/28 に Amazon ECR が OCI Artifact をサポートしました。
これにより Helm charts や OPA Bundles など、コンテナイメージ以外の
コンテンツタイプ (アーティファクト) を ECR で保存、配布できるようになります。OCI Artifact Support In Amazon ECR
https://aws.amazon.com/jp/blogs/containers/oci-artifact-support-in-amazon-ecr/例えば組織内で安全に Helm charts を共有しようとした場合に
これまでは ChartMuseum 等を使用して、プライベートな
Helm chart registry を構築する必要がありましたが、ECR だけで管理できるようになります。8/17の AWS Container Day at KubeCon で Developer Preview として発表されたばかりだった
認識ですが、2週間もたたずに正式リリース?となったようです。
今回のローンチの対象は SDK と CLI のサポートで、マネジメントコンソール側の変更は
今年後半にリリース予定とのこと。ほぼドキュメント通りの手順になってしまいますが、やってみます。
作業環境
- Helm: v3.3.0
- AWS CLI: 2.0.43
- Kubernetes: 1.16.5 (Docker Desktop)
Helm のインストール
クライアント端末に Helm 3 がインストールされていない場合はインストールしておきます。
Github のリリースページからバイナリを取得、インストールスクリプトの使用、
パッケージマネージャー経由など複数のインストール方法が準備されています。Installing Helm
https://helm.sh/docs/intro/install/$ helm version version.BuildInfo{Version:"v3.3.0", GitCommit:"8a4aeec08d67a7b84472007529e8097ec3742105", GitTreeState:"dirty", GoVersion:"go1.14.7"}Helm 3 における OCI のサポートは 現在 experimental な機能とみなされているため
HELM_EXPERIMENTAL_OCI
を環境変数に設定する必要があります。export HELM_EXPERIMENTAL_OCI=1
ECR レポジトリの作成と認証
AWS CLI で作成します。
特に追加のオプション等は不要で、いつもどおり作成できます。$ aws ecr create-repository --repository-name helm-test { "repository": { "repositoryArn": "arn:aws:ecr:ap-northeast-1:123456789012:repository/helm-test", "registryId": "123456789012", "repositoryName": "helm-test", "repositoryUri": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test", "createdAt": "2020-08-29T12:22:02+09:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": false }, "encryptionConfiguration": { "encryptionType": "AES256" } } }以下のコマンドで Helm クライアントを ECR に認証します。
$ aws ecr get-login-password | helm registry login \ > --username AWS --password-stdin 123456789012.dkr.ecr.region.amazonaws.com Login succeeded
aws ecr get-login
コマンドは非推奨になっており、AWS CLI v2 では削除されているため
aws ecr get-login-password
を使用します。参考:AWS CLIでECRにログインする時はget-loginではなくget-login-passwordを使おう
https://qiita.com/hayao_k/items/3e4c822425b7b72e7fd0Chart の作成
helm create
コマンドで Chart の雛形を作成することができます。$ mkdir helm-test $ cd helm-test $ helm create mychart Creating mychart今回はこの雛形をそのまま利用します。
ECR へ Push
helm chart save
コマンドで Chart ディレクトリをローカルキャッシュに保存します。
この際、リモートの ECR の URI を使用して、エイリアスを作成します。
このあたりは、コンテナイメージを push するときと同じ感覚です。$ helm chart save mychart mychart ref: mychart:0.1.0 digest: c455f9c99430ee099ea66999a40a0978947ccfd76e6922cdb8a911491326b0ed size: 3.5 KiB name: mychart version: 0.1.0 0.1.0: saved $ helm chart save mychart 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart ref: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart digest: 4865989e73df2c14b15ee2a1befa11673e455cc5a728239a05f5bc12b13cadb3 size: 3.5 KiB name: mychart version: 0.1.0 mychart: saved $ helm chart list REF NAME VERSION DIGEST SIZE CREATED 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-te... mychart 0.1.0 4865989 3.5 KiB 28 seconds mychart:0.1.0 mychart 0.1.0 4865989 3.5 KiB About a minute
helm chart push
コマンドで ECR に push できます。$ helm chart push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test] ref: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart digest: 4865989e73df2c14b15ee2a1befa11673e455cc5a728239a05f5bc12b13cadb3 size: 3.5 KiB name: mychart version: 0.1.0 mychart: pushed to remote (1 layer, 3.5 KiB total)今回のリリースではマネジメントコンソールに変更が入っていないため、
現在は普通に Docker イメージが格納されているだけのように見えます。push した Chart を確認すると、適切な artifactMediaType で保存されていることがわかります。
$ aws ecr batch-get-image --repository-name helm-test --image-ids imageTag=mychart --query 'images[].imageManifest' [ "{\"schemaVersion\":2,\"config\":{\"mediaType\":\"application/vnd.cncf.helm.config.v1+json\",\"digest\":\"sha256:65a07b841ece031e6d0ec5eb948eacb17aa6d7294cdeb01d5348e86242951487\",\"size\":141},\"layers\":[{\"mediaType\":\"application/tar+gzip\",\"digest\":\"sha256:acd033c1b722f7dcbfb38a909c422540c584feef52ad4aedb8289eb074638f27\",\"size\":3562}]}" ]ECR から Chart を pull する
pull を確認するため、
helm chart remove
コマンドで ローカルキャッシュ上の Chart を削除します。$ helm chart remove 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart mychart: removed $ helm chart remove mychart:0.1.0 0.1.0: removed
helm chart pull
コマンドで pull します。$ helm chart pull 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart mychart: Pulling from 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test ref: 123456789012.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart digest: 4865989e73df2c14b15ee2a1befa11673e455cc5a728239a05f5bc12b13cadb3 size: 3.5 KiB name: mychart version: 0.1.0 Status: Downloaded newer chart for 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart $ helm chart list REF NAME VERSION DIGEST SIZE CREATED 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-te... mychart 0.1.0 4865989 3.5 KiB 9 hoursChart のデプロイ
pull した Chart を使用して Kubernetes にデプロイするには
helm chart export
コマンドを使用して一度ローカルに export する必要があります。helm chart export 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart --destination ./chart-install ref: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/helm-test:mychart digest: 4865989e73df2c14b15ee2a1befa11673e455cc5a728239a05f5bc12b13cadb3 size: 3.5 KiB name: mychart version: 0.1.0 Exported chart to chart-install\mychart/
helm install
コマンドで Namespce: helm-test に Chart をインストールします。$ cd chart-install $ kubectl create ns helm-test namespace/helm-test created $ helm install mychart ./mychart -n helm-test NAME: mychart LAST DEPLOYED: Sun Aug 30 11:28:24 2020 NAMESPACE: helm-test STATUS: deployed REVISION: 1 NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace helm-test -l "app.kubernetes.io/name=mychart,app.kubernetes.io/instance=mychart" -o jsonpath="{.items[0].metadata.name}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace helm-test port-forward $POD_NAME 8080:80問題なくデプロイできました。
$ kubectl get all -n helm-test NAME READY STATUS RESTARTS AGE pod/mychart-5965fbff94-xxnd2 1/1 Running 0 32s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/mychart ClusterIP 10.99.155.110 <none> 80/TCP 32s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/mychart 1/1 1 1 32s NAME DESIRED CURRENT READY AGE replicaset.apps/mychart-5965fbff94 1 1 1 32s $ helm list -n helm-test NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mychart helm-test 1 2020-08-30 11:28:24.6691172 +0900 JST deployed mychart-0.1.0 1.16.0削除は
helm uninstall
コマンドを使用します。$ helm uninstall mychart -n helm-test release "mychart" uninstalled $ kubectl delete ns helm-test namespace "helm-test" deletedChart を ECR から削除する
ECR 上の Chart を削除する手順は、Docker イメージの時と変わりません。
$ aws ecr batch-delete-image --repository-name helm-test --image-ids imageTag=mychart { "imageIds": [ { "imageDigest": "sha256:4865989e73df2c14b15ee2a1befa11673e455cc5a728239a05f5bc12b13cadb3", "imageTag": "mychart" } ], "failures": [] }参考
Pushing a Helm chart
https://docs.aws.amazon.com/AmazonECR/latest/userguide/push-oci-artifact.html以上です。
参考になれば幸いです。
- 投稿日:2020-08-30T10:58:44+09:00
[docker][nginx] nginxで簡易ALBを作る
開発、テスト用に複数のアプリを立ち上げたかったので、簡単な ALBツールを作ってみました。(環境はAWS)
ツールを作ることにしたのは、以下のような制約があったからです。制約:
- サーバ外へ任意のポート公開ができない (80/443のみ)
- ALB 立ち上げ禁止 (本来ならコレ)アプローチとしては、docker を使っているので nginx のデフォルトのコンテナを使って実現することを考えます。
元々やりたいのはホスト上で複数のアプリを並行稼働させることなので、それぞれ別のポートを割り振って立ち上げておいて、nginx でホスト名によって振分けする形を目指します。振分け先は同じホストで動いている他のコンテナなので、nginx からみるとコンテナ内からホストへ接続することになります。
なお、ツールとしての簡易版なので、docker イメージを新たに作ったり、プラグイン追加はしないという範囲で進めます。
作成したツールは GitHub に置きました。
https://github.com/batatch/simple-alb概要
簡易版とはいいつつ、設定内容は AWS ALB のものを模して定義ファイルを用意して、そこから nginx の設定を生成→docker 実行のような構成を目指します。
手順:
$ make build # 定義ファイルから nginx 設定ファイルを生成 $ make up # docker-compose で設定ファイルを割り当てて nginx のコンテナを起動 $ make down # docker-compose で nginx のコンテナを停止定義ファイル:
alb.yml--- http: listen: 80 # リスナー、今回は HTTPのみ rules: - if: # ALB の IF 条件 host: app01.example.com # ホスト名マッチング pathes: [ "/" ] # パスマッチング then: # ALB の THEN 文 forward: # 転送設定 name: tg-app01 targets: # 転送先(複数)、ターゲットグループのようなイメージ - target: http://docker0:21080 weight: 30 - target: http://docker0:22080 stickiness: true :手順は Makefile にまとめます。
好みですが、これが最も手軽で分かりやすいと思います。
それから、上記の定義ファイルを元に、以下のような nginx の設定ファイルを作成します。nginx/conf.d/default.confupstream target1 { server http://docker0:21080; server http://docker0:22080; } server { listen 80; server_name app01.example.com; : location / { proxy_pass http://target1; } }枠組みはこんな感じ。
テンプレートエンジン
設定ファイルを自動生成するので、なんらかのテンプレートエンジンが欲しいと思って、Ansible などで使われている Python の Jinja2 を使ってみます。
以下のような簡単な Python スクリプトで、テンプレートファイルと、設定ファイルの YAML ファイルから変換結果を得られるようにしました。
j2.pyimport sys import yaml from jinja2 import Template, Environment, FileSystemLoader def _j2(templateFile, configFile): env = Environment(loader=FileSystemLoader('.', encoding='utf_8')) tpl = env.get_template(templateFile) with open(configFile) as f: conf = yaml.load(f) ret = tpl.render(conf) print(ret) if __name__ == '__main__': if (len(sys.argv) <= 2): print("Usage: j2.pl <template file> <config file>") sys.exit(-1) _j2(sys.argv[1], sys.argv[2])コマンドラインはこんな感じ。
$ python j2.pl template.conf.j2 param.yml > output.confdockerコンテナからホストへの通信
これがなかなか面倒で、Windowsや Macの Docker環境であれば host.docker.internal で、コンテナ内→ホストへの接続ができるようですが、Linux ではそのような方法が用意されていません。
Linux では docker0 というインターフェースでホスト/コンテナ間をつないでいるらしいので、ホスト側で docker0 に振られた IPアドレスを取得し、環境変数化して docker 起動時に渡すようにしました。
$ env DOCKER0_ADDRESS=$( ip route | awk '/docker0/ {print $9}' ) \ docker-compose up -ddocker-compose.ymlversion: '3' services: alb: image: nginx:stable : extra_hosts: - "docker0:${DOCKER0_ADDRESS}"docker-compose.yml にて extra_hosts にマッピングを書いておくと、コンテナ起動時にコンテナ内の /etc/hosts にホスト名とIPアドレスのマッピングが追記されるので、nginx の設定で名前参照できるようです。
/etc/hosts ---- 172.17.0.1 docker0nginx でロードバランサ
nginx でロードバランサを設定するには http/upstream でターゲットのグループを定義して、http/server/location の proxy_pass で upstream 名を指定する。。想定だったのですが、エラーで起動しません。
どうやら nginx の無償版では upstream 内に書かれたホスト名の DNS解決(resolver) が使えないようです。
(nginx に有償版/無償版があるのを、今回初めて知りました。。)この件についてまとめられた記事です。
下の Qiita の記事で UNIX ソケットを使う方法が紹介されています。
プラグイン使ったり、docker イメージ作成しないという制約に合っていたので、今回はこちらを採用しました。(設定ファイルが長くなりますが)Nginxの名前解決についてまとめ
https://ktrysmt.github.io/blog/name-specification-of-nginx/
nginxのupstreamコンテキストで有償のresolveオプションを使わずに動的にDNS解決する
https://qiita.com/minamijoyo/items/183e51a28a3a9d79182fnginx/conf.d/default.confupstream tg-app01 { server unix:/var/run/nginx_tg-app01_1; # (2-1) tg-app01の 1つめのターゲット server unix:/var/run/nginx_tg-app01_2; # (2-2) tg-app01の 2つめのターゲット } server { listen 80; server_name app01.example.com; : location / { proxy_pass http://tg-app01; # (1) upstream tg-app01 を参照 } } server { listen unix:/var/run/nginx_tg-app01_1; # (2-1) 1つめのターゲットの参照先 server_name app01.example.com; : location / { proxy_pass http://docker0:21080; } } server { listen unix:/var/run/nginx_tg-app01_2; # (2-2) 2つめのターゲットの参照先 server_name app01.example.com; : location / { proxy_pass http://docker0:22080; } }Websocket の疎通
今回 Websocket を通す必要があったので、以下の設定を行います。
各 server ブロックに必要なようです。nginx/conf.d/default.conf# これと map $http_upgrade $connection_upgrade { default upgrade; '' close; } : server { listen 80; server_name app02.example.com; # ここから proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # ここまで location / { proxy_pass http://tg-app02; } }nginx 設定ファイルのテンプレート
ここまでの内容を踏まえて、テンプレート定義は以下のようになりました。
細かいですが、+α でデフォルトパターンの指定や固定レスポンスの設定も入っています。src/default.conf.j2## http listener settings map $http_upgrade $connection_upgrade { default upgrade; '' close; } {% for rule in http.rules %} {%- if rule.then.forward %} upstream {{ rule.then.forward.name }} { {%- if rule.then.forward.stickiness %} ip_hash; {%- endif %} {%- for tg in rule.then.forward.targets %} server {{ 'unix:/var/run/nginx_%s_%d' % (rule.then.forward.name, loop.index) }}{{ ' weight=%d' % tg.weight if tg.weight else '' }}; {%- endfor %} } {%- endif %} server { listen {{ http.listen }}{{ ' default_server' if rule.if.default_server }}; server_name {{ rule.if.host }}; {% if rule.then.forward %} proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; {% endif %} {%- for path in rule.if.pathes %} location {{ path }} { {%- if rule.if.headers %} {%- for header in rule.if.headers %} if ($http_{{ header|replace('-','_')|lower() }} = "{{ rule.if.headers[header] }}") { proxy_pass http://{{ rule.then.forward.name }}; break; } {%- endfor %} {%- else %} proxy_pass http://{{ rule.then.forward.name }}; {%- endif %} } {%- endfor %} {%- if rule.then.response %} location / { {%- if rule.then.response.content_type %} default_type {{ rule.then.response.content_type }}; {%- endif %} return {{ rule.then.response.code }}{{ ' \'%s\'' % rule.then.response.message if rule.then.response.message }}; } {%- endif %} } {%- if rule.then.forward %} {%- for tg in rule.then.forward.targets %} server { listen {{ 'unix:/var/run/nginx_%s_%d' % (rule.then.forward.name, loop.index) }}; server_name {{ rule.if.host }}; {% if rule.then.forward %} proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; {% endif %} location / { proxy_pass {{ tg.target }}; } } {%- endfor %} {%- endif %} {% endfor %}docker-compose 設定は以下のとおり。
nginx の設定フォルダを外部ボリュームにマウントして、設定を反映させます。docker-compose.ymlversion: '3' services: alb: image: nginx:stable ports: - "80:80" volumes: - ./conf.d:/etc/nginx/conf.d extra_hosts: - "docker0:${DOCKER0_ADDRESS}" restart: always動作確認は以下のとおり。
$ make build # 設定ファイル変換 $ make up # nginx コンテナ起動 $ curl http://localhost:80 -i -H "Host:app01.example.com" # ホスト名を設定してアクセス HTTP/1.1 200 OK Server: nginx/1.18.0 Date: Sat, 29 Aug 2020 17:26:23 GMT Content-Type: text/html Content-Length: 1863 Connection: keep-alive Last-Modified: Wed, 11 Mar 2020 05:22:13 GMT ETag: "747-5a08d6b34ab40" Accept-Ranges: bytes <!DOCTYPE html> <html> :まとめ
AWS ALB っぽい構成要素を YAML 定義に書いて、複雑な nginx の設定を書かなくていいので、管理もしやすくなると思います。
ビルドやプラグインのインストールも不要なので、DockerHub から nginx のイメージの取得さえできれば簡単に ALB 気分になれます。nginx の設定の勉強にもなりました。(無償版/有償版も知らなった。。)
もっと調べ込んで頑張れば、ALB 本家の設定パターンを実現できるかもしれないですね。(今回はできるだけ手軽に使えるレベルにしたかったので、作り込みはしないようにしました)
- 投稿日:2020-08-30T09:52:24+09:00
【Rails環境構築】Docker + Rails + MySQL (初心者も30分でOK!)
Dockerを使った環境構築
「環境構築はコードを書くよりも難しい」と聞いたことがあります。
Dockerは簡単!
何故かと言うと、、、
コピペするだけでいいから
ただし、理解するまで少し時間がかかるかも、、、
まずは簡単な概要からDocker
仮想環境を構築するための道具
コンテナ
仮想環境そのもの
(DockerはDockerエンジンの上にコンテナが動く)イメージ
Dockerコンテナを実行するために必要なもの。
環境構築の手順
①.
プロジェクト(ディレクトリ)を作成し、移動する
$ mkdir アプリ名 $ cd アプリ名②.
Dockerfile、docker-compose.yml、Gemfile、Gemfile.lockを作成する
$ touch Dockerfile docker-compose.yml Gemfile Gemfile.lock③.
エディタを開き、Dockerfile、docker-compose.yml、Gemfileを下記からコピペする
Dockerfile
Dockerのイメージを自動で生成してくれるファイル
FROM ruby:2.5 RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs RUN mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myappFROM : 使用するイメージとコマンド
RUN : コマンドの実行
WORKDIR : 作業ディレクトリの設定
COPY : コピー元(ホスト側)とコピー先(仮想環境側)のファイルまたはディレクトリを指定Gemfile
source 'https://rubygems.org' gem 'rails', '~> 5.2.3'docker-compose.yml
version: '3' services: db: image: mysql:5.7 environment: MYSQL_USER: root MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" volumes: - ./db/mysql/volumes:/var/lib/mysql web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp - gem_data:/usr/local/bundle ports: - 3000:3000 depends_on: - db tty: true stdin_open: true volumes: gem_data:version : docker-composeのバージョン。
depends_on : 依存関係を示していて起動順を制御できる。ここでは「db→web」へ起動する。Docker composeとは
Docker composeとは、複数のコンテナから成るサービスを構築・実行する手順を自動化し、管理を容易にする機能。Docker composeでは、composeファイルを用意してコマンドを一回実行することで、そのファイルから設定を読み込んですべてのコンテナを起動することができる。
serviceについて
Docker composeでは、アプリケーションを動かすための各要素をserviceと呼んでいる。通常はweb(rails)とdb(mysql)と名付ける。
rm -f tmp/pids/server.pid
についてpidとはプロセスIDのことである。pidは、開発用Webサーバーを起動するときにtmp/pids/server.pidに書き込まれ、終了するときに削除される。server.pidにpidが書かれているとサーバーが起動中と判断されてしまう。
portsについて
ports: - 3000:3000上記は、コンテナ内のポート3000番をホストの3000番にマッピングするという意味。これにより、コンテナ内のWebサーバーへ
http://localhost:3000
でアクセスできるようになる。volumeについて
volumes: - ./db/mysql/volumes:/var/lib/mysqlは、ホストの./db/mysql/volumesをコンテナ内の/var/lib/mysqlにマウントするという意味。簡単にいうと、Dockerのコンテナと、ローカルを同期している。
volumes : - .:/myappは
.
がホストのディレクトリ全てを意味し、それをコンテナ内のmyapp
にマウントしている。④.
下記コマンドを実行する
$ docker-compose run web rails new .--force --database=mysql --skip-bundlerunコマンドではimageの構築から、コンテナの構築・起動までしてくれる。
引数にサービスを指定する必要あり。
docker-compose.ymlのvolumes:- .:/myappの部分でdockerとローカルのディレクトリを同期するように設定しているため、このコマンドを実行後、同時にローカルにも同様のファイルが生成される。⑤.
config/database.yml内の(password: password、host: db)に変更する
default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password #passwordを追記しました host: db #localhostからdbに変更しました⑥.
下記コマンドを実行する
$ docker-compose buildGemfileが更新されたとき
build
を実行する⑦.
下記コマンドを実行する
$ docker-compose up -ddocker-compose.yml通りにコンテナが起動する。
docker-compose.ymlの変更を反映させる際にも実行。
-d
オプションはバックグラウンド起動。⑧.
下記コマンドを実行する
$ docker-compose run web rails db:createデータベースを作成する。
docker-compose run web
でローカルからコマンドを実行できる。(コンテナに入る必要はない)⑨.
下記コマンドを実行し、2つのコンテナが立ち上がっているか確認する。
(完成!)$ docker ps現在起動しているコンテナを表示するコマンド。
localhost:3000
にアクセスするといつものYay!You're on Rails!が表示される。
コンテナを削除したい場合は下記を実行する
$ docker-compose down
docker ps
でコンテナが削除されているか確認する。
またコンテナを生成・起動する場合はdocker-compose up -d
を実行する。まとめ
かなり簡単だったんじゃないかなと思います!
これでアプリ開発していきましょう!
- 投稿日:2020-08-30T00:49:32+09:00
初めてopenvinoのface_detectionに触て、及び出会った問題
環境:
centOS7
Docker19.03.12
python3.8.5OpenVINO™ Model Server---face_detection
https://github.com/openvinotoolkit/model_server
#最新モデルサーバイメージをダウンロード docker pull openvino/ubuntu18_model_server:latest #モデルをダウンロード curl --create-dirs. https://download.01.org/opencv/2020/openvinotoolkit/2020.2/open_model_zoo/models_bin/3/face-detection-retail-0004/FP32/face-detection-retail-0004.xml https://download.01.org/opencv/2020/openvinotoolkit/2020.2/open_model_zoo/models_bin/3/face-detection-retail-0004/FP32/face-detection-retail-0004.bin -o model/face-detection-retail-0004.xml -o model/face-detection-retail-0004.bin # 9000ポートでgRPC用のコンテナを起動 docker run -d -v $(pwd)/model:/models/face-detection/1 -e LOG_LEVEL=DEBUG -p 9000:9000 openvino/ubuntu18_model_server /ie-serving-py/start_server.sh ie_serving model --model_path /models/face-detection --model_name face-detection --port 9000 --shape auto #クライアントスクリプトのダウンロード curl https://raw.githubusercontent.com/openvinotoolkit/model_server/master/example_client/client_utils.py -o client_utils.py https://raw.githubusercontent.com/openvinotoolkit/model_server/master/example_client/face_detection.py -o face_detection.py https://raw.githubusercontent.com/openvinotoolkit/model_server/master/example_client/client_requirements.txt -o client_requirements.txt #分析するイメージをダウンロード curl --create-dirs https://raw.githubusercontent.com/openvinotoolkit/model_server/master/example_client/images/people/people1.jpeg -o images/people1.jpeg #クライアント依存関係のインストール pip install -r client_requirements.txt #結果のフォルダを作成 mkdir results #推論を実行し、結果を新しく作成したフォルダに保存 python face_detection.py --batch_size 1 --width 600 --height 400 --input_images_dir images --output_dir results問題点は:
ModuleNotFoundError: No module named 'cv2’
解決:pip install opencv-pythonModuleNotFoundError: No module named 'grpc'
解決:python -m pip install grpcioModuleNotFoundError: No module named 'tensorflow'
解決:pip install --upgrade --ignore-installed tensorflowModuleNotFoundError: No module named 'tensorflow_serving'
解決:pip install tensorflow-serving-api
- 投稿日:2020-08-30T00:42:42+09:00
In file './docker-compose.yml', the service name True must be a quoted string, i.e. 'True'.
DockerでRailsの環境構築中 docker-compose run web rails new . --force --no-deps --database=postgresql --skip-bundle をしたら、
In file './docker-compose.yml', the service name True must be a quoted string, i.e. 'True'.
のエラーが出たのでメモします。原因
誤字
e: '3' services: db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - "3000:3000" depends_on: - dbe: '3'
ここを
version: '3'
に修正したら、動いた修正後
version: '3' services: db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - "3000:3000" depends_on: - db
- 投稿日:2020-08-30T00:20:26+09:00
Python製WebアプリケーションをDockerで運用する
前回:EmbyをDockerで運用する
これはそろそろDockerを使えるようになりたい筆者の試行錯誤の軌跡です。Python製WebアプリケーションをDockerで
前回はメディアストリーミングサービスのEmbyをコンテナに移行しました。
今回はPython製Webアプリケーションを展開できるDockerイメージを作り、
Web Socket使用のアプリケーションとDjangoアプリケーションをDockerに移行します。
ついでに静的コンテンツもコンテナに移動し、VMサーバーを閉じます。
静的コンテンツ
VMサーバーにあったものをDockerホストに移動し、コンテナ起動時に配信ディレクトリへバインドしました。
docker-compose.ymldeploy: image: nginx restart: always ports: - 80:80 - 443:443 volumes: - /home/fclef/docker/server/deploy/nginx/conf:/etc/nginx/conf.d + - /home/fclef/docker/server/deploy/content/html:/usr/share/nginx/html
Python製アプリケーションのDocker運用
Web Socket使用アプリケーションもPython製(bottle)なので、Python製アプリケーションを簡単に展開できるコンテナを目指します。
コンテナ設計
僕はよくPythonでWebアプリケーションを作ります。
なので、アプリケーションごとイメージに固めてしまうというよりは、
どんなPythonアプリケーションでも動かせる土台をイメージ化し、
具体的なアプリケーション自体はgitの情報をコンテナ起動時に渡して、コンテナ内でクローン、展開させます。
Dockerfile
僕がPythonで何かを作るときは必ずPipenvを使います。
また、Webアプリケーションのときはソケット化してnginxで配信するので、
イメージの時点でPipenv, nginxをインストールしておきます。DockerfileFROM python:3.8-slim-buster # 依存パッケージのインストール RUN apt-get -y update RUN apt-get -y upgrade RUN apt-get install -y git make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libs qlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev nginx # Pyenvのインストール RUN git clone https://github.com/yyuu/pyenv.git /.pyenv ENV PYENV_ROOT /.pyenv ENV PATH $PYENV_ROOT/bin:$PATH RUN pyenv init - | bash # Pipenvのインストール RUN pip install pipenv ENV PIPENV_VENV_IN_PROJECT 1 ENV PIPENV_YES true RUN mkdir /app # アプリケーション配備ディレクトリ RUN mkdir /script # 各種スクリプト配置ディレクトリ COPY up.sh /script # 起動スクリプト # 起動スクリプト内でgitプロジェクトをappにクローンするので移動しておく WORKDIR /app # Webアプリケーションの配信はメインWebサーバを介するリバースプロキシなので、80ポートだけ空けておく EXPOSE 80 RUN chmod +x /script/up.sh ENTRYPOINT [ "/script/up.sh" ] # コンテナ起動時、起動スクリプトup.shを実行するコンテナ起動スクリプト
アプリケーションのgit情報はコンテナ起動時に環境変数で渡します。
僕の環境ではなぜかsshでのgitのクローンができないため、httpsでクローンする前提です。
クローンしたら、プロジェクトルートディレクトリにあるPipfileを解析し、必要なPythonバージョンを決定します。
Pythonライブラリの中には、依存するプログラムがインストールされている必要があるケースがあるので、
それらをインストールするためのスクリプト(dependencies.sh)をコンテナ起動時にバインドしておき、ここで呼び出します。
Python製Webアプリケーションのソケット化はgunicornを使うので、gunicornもインストールしておきます。up.sh#!/bin/bash # 環境変数からgit情報を取得する gitCloneUrl=${GIT_CLONE_URL} gitUserName=${GIT_USER_NAME} gitPassword=${GIT_PASSWORD} gitCloneTarget=`echo ${gitCloneUrl} | sed -r "s#^(https?://)(.*)#\1${gitUserName}:${gitPassword}@\2#g "` # プロジェクト名を取得する projectName=`echo ${gitCloneUrl} | sed -r "s#.*/(\w+)\.git#\1#g"` echo "■ ■ ■ PROJECT NAME <${projectName}> ■ ■ ■" git clone ${gitCloneTarget} # Pipfileからpythonバージョンを取得する cd ${projectName} pythonVersion=`grep python_version Pipfile | sed -r 's/python_version = "(.+)"/\1/g'` echo "■ ■ ■ PYTHON VERSION <${pythonVersion}> ■ ■ ■" # インストールするPythonライブラリの中に他プログラムに依存するものがある場合は、ここでインストールしておく。 if [ -f /script/dependencies.sh ]; then source /script/dependencies.sh fi pipenv --python ${pythonVersion} pipenv install pipenv install gunicorn curPath=`pwd` export APP_ROOT=${curPath} chmod +x /script/run.sh service nginx start /script/run.sh # アプリケーション起動スクリプト while true; do sleep 1000; doneコンテナの起動
例として、Djangoアプリケーションを起動する構成をお見せします。
docker-compose.yml抜粋django: image: pipenv-gunicorn restart: always environment: GIT_CLONE_URL: https://xxxxxxxx/user/project.git GIT_USER_NAME: user GIT_PASSWORD: password volumes: - /home/fclef/docker/server/app/dependencies.sh:/script/dependencies.sh - /home/fclef/docker/server/app/run.sh:/script/run.sh - /home/fclef/docker/server/app/app.conf:/etc/nginx/conf.d/nginx_gunicorn.co nf depends_on: - deploy - gitlabdependencies.shapt-get -y --no-install-recommends install libpq-devrun.shcd /app/project source .venv/bin/activate python manage.py collectstatic --noinput python manage.py makemigrations python manage.py migrate deactivate /app/project/.venv/bin/gunicorn \ --access-logfile /var/log/socket_success.log \ --error-logfile /var/log/socket_error.log \ --workers 1 \ --bind unix:/run/socket.sock \ config.wsgi:applicationapp.confserver { listen 80; listen [::]:80; server_name xxxx.xxx.xxx; root /app; location /static { alias /app/project/static; } location / { include /etc/nginx/proxy_params; proxy_pass http://unix:/run/socket.sock; } location ~ ^/apple-touch-icon(.*)\.png$ { root /app/project/; rewrite ^/apple-touch-icon(.+)\.png$ /static/img/apple-touch-icon.png break; } }アプリケーション本体はコンテナ起動時にgitからクローン、
データは別コンテナのPosgreSQLに保存してあるので、
このコンテナは何度作成し直しても正常に運用状態のサービスを展開できます。基本的に上記イメージと起動方法で大抵のPythonアプリケーションは動かせるようになりました。
gitクローンからデプロイまでの手順が単純なのでアプリケーションを外出しして再利用しやすいイメージが作成できましたが、
環境構築が複雑なアプリケーションの場合は、アプリケーションごとイメージにしてしまった方が保守性があがるかもしれません。以上、VMサーバー群をコンテナに移行するシリーズでした。
- 投稿日:2020-08-30T00:06:49+09:00
S3 と同等の機能を持つ MinIOの使用方法 docker-compose を使用
概要
諸所諸々の事情(契約の問題や予算など)でAWSのサービスが使えない状況でも開発するためにdockerで使えるようにしてみました。
タイトルはMinIOですがほかにDynamoDB,MySQLも使えるようにしてあります。事前準備
- dockerをまず導入します。windows Homeの場合は Docker Quickstart Terminal を使います。
- アプリの方はPythonを使っているため pythonのインストール(記事作成時は3.7です)。
- JupyterNotebookなどでも可能です。
- boto3
docker-compose
- 今回は
docker-compose
で起動させるためymlを作成します。- MinIO以外にMySQLとDynamoDBも使えるようにしています。
最終的なファイルは以下になります。
docker-compose.yml
version: '3.7' services: dynamodb-local: build: ./dynamodb volumes: - dynamodb_data:/home/dynamodblocal/data ports: - 8000:8000 command: -jar DynamoDBLocal.jar -dbPath ./data mysql: image: mysql:5.7 command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: 'password' ports: - 3306:3306 minio1: image: minio/minio:RELEASE.2020-08-27T05-16-20Z volumes: - data1-1:/data1 - data1-2:/data2 ports: - "9000:9000" environment: MINIO_ACCESS_KEY: minio MINIO_SECRET_KEY: minio123 command: server data1 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 volumes: dynamodb_data: db_data: {} data1-1: data1-2:
- DynamoDBのDockerファイル
FROM amazon/dynamodb-local WORKDIR /home/dynamodblocal # UID=1000 → DynamoDB Local の実行ユーザ RUN mkdir data && chown -R 1000 data
- 起動すると以下のようにエンドポイントが表示されているのでメモ等取っておきます。
- Docker Quickstart Terminal の場合はIPアドレスの部分をdocker 起動時に表示されるIPに読み替えてください。
minio1_1 | Endpoint: http://172.20.0.4:9000 http://127.0.0.1:9000 minio1_1 | minio1_1 | Browser Access: minio1_1 | http://172.20.0.4:9000 http://127.0.0.1:9000
http://192.168.99.100:9000/minio/
(Docker Quickstart Terminal のためIPアドレスが違っています)にアクセスすることでブラウザ上でバケットの中などの確認や作成などを行うことができます。S3機能の実装
- bucketの作成~ファイルアップロードまでのソースは以下のようになります。
- S3にアップロードする際のディレクトリ構成を
os.path.join
で作成すると\\
で接続されてしまうのでreplaceで変換しています。import boto3 import os from datetime import datetime endpoint_url = os.getenv('S3_ENDPOINT', 'http://192.168.99.100:9000/') aws_access_key_id = os.getenv('S3_ACCESS_KEY_ID', 'minio') aws_secret_access_key_id = os.getenv('S3_SECRET_ACCESS_KEY_ID', 'minio123') s3 = boto3.resource( 's3', aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key_id, endpoint_url=endpoint_url ) bucket=s3.Bucket('testbukcet') bucket.create() bucketPath=os.path.join('dir',datetime.now().strftime('%Y%m%d%H%M%S'),'out','test.csv') filePath=bucketPath.replace('\\','/') bucket.upload_file('test.csv',filePath)