- 投稿日:2020-02-17T22:53:10+09:00
Docker on WSL
Windows10のWSL上にDockerをインストールしたメモ
ソフトウエア環境
Windows 10 Home Ver. 1809 (build 17763.1039)
Ubuntu 18.04.02 LTS (on Windows subsystem for Linux)手順
WSLとUbuntuのインストール
割愛
Dockerのインストール
※以下の作業はWSLを管理者権限で実行すること
(net stop LxssManagerでサービス停止後に管理者権限で起動すると確実?)$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - $ sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" $ sudo apt-get update $ sudo apt-get install docker-ce=18.06.1~ce~3-0~ubuntu $ sudo usermod -aG docker $USERaptでインストールするパッケージにdocker.ioを選択しても動作している人もいるみたいですが、うちの環境ではダメでした。
docker-cdでも最新バージョンではうまく動かず18.06.1で動作確認できました。この後WSLを一度再起動してから下記のようにDockerデーモンを起動します。
$ sudo cgroupfs-mount $ sudo service docker start $ docker version Client: Version: 18.06.1-ce API version: 1.38 Go version: go1.10.3 Git commit: e68fc7a Built: Tue Aug 21 17:24:51 2018 OS/Arch: linux/amd64 Experimental: false Server: Engine: Version: 18.06.1-ce API version: 1.38 (minimum version 1.12) Go version: go1.10.3 Git commit: e68fc7a Built: Tue Aug 21 17:23:15 2018 OS/Arch: linux/amd64 Experimental: falseWSLを管理者権限で動作していないと
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?というエラーが表示され、デーモンが起動しません。
明示的に右クリックから管理者権限で起動してもたまにこのエラーが出ることがあります。
その時はPowerShellで下記のサービスを一旦落としてから起動するとうまくいきます。PS C:\Windows\system32> net stop LxssManager LxssManager サービスを停止中です. LxssManager サービスは正常に停止されました。また、Docker.ioパッケージでインストールした場合は
サービスの起動まではできるもののイメージをpullしようとするとError response from daemon: OCI runtime create failed: container_linux.go:346 (以下略)というエラーが出て使えませんでした。
その後
個人的な環境づくりのメモです。
$ docker run -v /c/usr:/var/c/usr -it ubuntu:latest // 以下はコンテナ内で # apt-get update # apt-get install language-pack-ja git参考
- 投稿日:2020-02-17T22:51:46+09:00
Dockerで起動したJupyterLabでvimキーバインドを使う
概要
前回Jupyter Notebookでvimのキーバインドが使えるようにしましたが、
JupyterLabの存在を完全に忘れていたので、、同様にDockerでJupyterLabを起動してvimのキーバインドが使えるようなやり方をまとめました。参考:Dockerで起動したJupyter Notebookでvimキーバインドを使う
Jupyter NotebookとJupyterLabの違い
Jupyter notebookの後継機がJupyterLabになってまして、基本的に出来ることはどちらでも同じですが、JupyterLabの方が高機能になっています。
Jupyter notebookの開発は一旦終了して今後はJupyterLabに置き換わるようです。環境
バージョン Mac 10.15.3 Docker 19.03.4 docker-compose 1.24.1 環境構築手順
Dockerfileとdocker-composeを使ってvimのキーバインドが使えるJupyterLabを起動します。
※以下ファイルはGitHubにもまとめているのでご参考ください。
https://github.com/hikarut/Data-Science1. notebook保存用のディレクトリ作成
$ mkdir notebooks2. Dockerfileの作成
DockerfileFROM jupyter/datascience-notebook USER root RUN pip install jupyterlab==1.0 RUN jupyter serverextension enable --py jupyterlab RUN jupyter labextension install jupyterlab_vim EXPOSE 10000 CMD ["bash"]※
jupyterlab_vim
がjupyterlab 1.0
にしか対応してないようなのでバージョンを指定してインストールしてます
jupyterlab-vim:https://github.com/jwkvam/jupyterlab-vim3. docker-compose.ymlの作成
docker-compose.ymlversion: '3' services: data-science: restart: always build: . container_name: 'data-science' ports: - "10000:10000" working_dir: '/root/' tty: true volumes: - ./notebooks:/root/notebooks/4. コンテナのビルド
$ docker-compose up -d --build5. コンテナにログイン
$ docker-compose exec data-science bash6. Jupyter Notebookの起動
/root# jupyter lab --port 10000 --allow-root表示される
http://127.0.0.1:10000/?token=xxxxxxxxxxxxxxxx
にアクセスします。Jupyter Notebookの時のように設定変更する必要もなく、そのままの状態でnotebook上でvimが使えるようになります
最後に
JupyterLabの方がJupyter Notebookよりも気持ちセットアップが楽でした!
(今回もユーザーを全てrootにしちゃったのでその辺は変えた方が良いかもです。。。)
ただjupyterlab-vimのビルドがめちゃくちゃ遅いのが気になりましたが、、今後改善されると嬉しいなと思います。参考
- 投稿日:2020-02-17T22:19:30+09:00
PostgresのDockerImageに変更があってログインができなくなった話
はじめに
DockerでLocalの開発環境としてPostgresの環境を構築していたんですが、
急に動かなくなってしまったのでメモがわりに残しておきます。環境
$ docker version Client: Docker Engine - Community Version: 19.03.5 API version: 1.40 Go version: go1.12.12 Git commit: 633a0ea Built: Wed Nov 13 07:22:34 2019 OS/Arch: darwin/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.5 API version: 1.40 (minimum version 1.12) Go version: go1.12.12 Git commit: 633a0ea Built: Wed Nov 13 07:29:19 2019 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.2.10 GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339 runc: Version: 1.0.0-rc8+dev GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657 docker-init: Version: 0.18.0 GitCommit: fec3683問題発生
docker-composeでPostgresのimageを設定してLocalで開発環境を構築していました。
ところが今日(2020/02/17)起動した際に急に動かなくなる自体が発生。docker-compose.yml(抜粋)services: db: image: postgres
docker-compose up
で起動した際に以下のエラーが出ました。Error: Database is uninitialized and superuser password is not specified. You must specify POSTGRES_PASSWORD for the superuser. Use "-e POSTGRES_PASSWORD=password" to set it in "docker run". You may also use POSTGRES_HOST_AUTH_METHOD=trust to allow all connections without a password. This is *not* recommended. See PostgreSQL documentation about "trust": https://www.postgresql.org/docs/current/auth-trust.html調査
エラーの内容をみる限りはスーパーユーザーのパスワードが指定されていなかったことに起因するもので、
対応すべき内容も書いてあります。
一応該当のエラーで検索してみると以下のページにたどり着きました。
ちょうどこのページも3日前にopenされた内容です。https://github.com/docker-library/postgres/issues/681
どうやら以下のコミットが5日ほど前にマージされた影響のよう。
該当のコミット
マージされたPR
https://github.com/docker-library/postgres/pull/658
今回は開発環境でパスワードが設定されていない状態でDBに接続していたので、
上記の改修で繋がらなくなってしまった模様。解決
今回は自分のlocal環境で開発する際に確認のために一度だけ繋がればよかったので
POSTGRES_HOST_AUTH_METHOD
オプションをtrust
にすることで対応しました。本来はきちんとパスワードを設定した方が良いです。
docker-compose.yml(抜粋)services: db: image: postgres environment: POSTGRES_HOST_AUTH_METHOD: 'trust' # POSTGRES_PASSWORD: 'postgres' ← envファイルに外出ししても良い終わり
今回は
- パスワードが設定されていなかった
- ちょうど週末にimageを整理した際にpostgresのimageを一回削除していた
ことからこの状況が発生してしまいました。
開発環境であってもきちんとパスワードを設定しておく、imageのversionをロックしておくことは大事だと言う教訓ですね。
(ちなみにpostgresのバージョンをpostgres:9.5.10
で指定した場合は発生せず)
- 投稿日:2020-02-17T22:19:30+09:00
PostgresのDockerImageに変更があって起動ができなくなった話
はじめに
DockerでLocalの開発環境としてPostgresの環境を構築していたんですが、
急に動かなくなってしまったのでメモがわりに残しておきます。環境
$ docker version Client: Docker Engine - Community Version: 19.03.5 API version: 1.40 Go version: go1.12.12 Git commit: 633a0ea Built: Wed Nov 13 07:22:34 2019 OS/Arch: darwin/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.5 API version: 1.40 (minimum version 1.12) Go version: go1.12.12 Git commit: 633a0ea Built: Wed Nov 13 07:29:19 2019 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.2.10 GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339 runc: Version: 1.0.0-rc8+dev GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657 docker-init: Version: 0.18.0 GitCommit: fec3683問題発生
docker-composeでPostgresのimageを設定してLocalで開発環境を構築していました。
ところが今日(2020/02/17)起動した際に急に動かなくなる自体が発生。docker-compose.yml(抜粋)services: db: image: postgres
docker-compose up
で起動した際に以下のエラーが出ました。Error: Database is uninitialized and superuser password is not specified. You must specify POSTGRES_PASSWORD for the superuser. Use "-e POSTGRES_PASSWORD=password" to set it in "docker run". You may also use POSTGRES_HOST_AUTH_METHOD=trust to allow all connections without a password. This is *not* recommended. See PostgreSQL documentation about "trust": https://www.postgresql.org/docs/current/auth-trust.html調査
エラーの内容をみる限りはスーパーユーザーのパスワードが指定されていなかったことに起因するもので、
対応すべき内容も書いてあります。
一応該当のエラーで検索してみると以下のページにたどり着きました。
ちょうどこのページも3日前にopenされた内容です。https://github.com/docker-library/postgres/issues/681
どうやら以下のコミットが5日ほど前にマージされた影響のよう。
該当のコミット
マージされたPR
https://github.com/docker-library/postgres/pull/658
今回は開発環境でパスワードが設定されていない状態でDBに接続していたので、
上記の改修で繋がらなくなってしまった模様。解決
今回は自分のlocal環境で開発する際に確認のために一度だけ繋がればよかったので
POSTGRES_HOST_AUTH_METHOD
オプションをtrust
にすることで対応しました。本来はきちんとパスワードを設定した方が良いです。
docker-compose.yml(抜粋)services: db: image: postgres environment: POSTGRES_HOST_AUTH_METHOD: 'trust' # POSTGRES_PASSWORD: 'postgres' ← envファイルに外出ししても良い終わり
今回は
- パスワードが設定されていなかった
- ちょうど週末にimageを整理した際にpostgresのimageを一回削除していた
ことからこの状況が発生してしまいました。
開発環境であってもきちんとパスワードを設定しておく、imageのversionをロックしておくことは大事だと言う教訓ですね。
(ちなみにpostgresのバージョンをpostgres:9.5.10
で指定した場合は発生せず)
- 投稿日:2020-02-17T19:01:57+09:00
社内向け Kubernetes Hands On(第1回 Pod編)
Kubernetes Hands On(第1回)
Podの考え方
Podとは大まかに
Containerの集合体と考えることが出来ます。
簡単に考えると、
docker-composeで作成されるContainer群がPodだと考えることが可能です。では、実際にPodを作成してみましょう。
pod.yamlapiVersion: v1 kind: Pod metadata: name: demo labels: name: demo spec: containers: - name: demo image: ncsnozominishinohara/demo:v1 resources: {} ports: - containerPort: 80解説
apiVersion
kubernetesのバージョンによって使用できる値は変わります。
kubernetesの所属しているAPIGROUPによって書き方が異なります。
- 特定のApiGroupに属している場合・・・apiVersion: ApiGroup/ApiVersion
- 特定のApiGroupに属していない場合(CoreGroupに属している)・・・apiVersion: ApiVersion
対応しているApiGroupの調べ方は以下のコマンドを実行することで確認出来ます。(v1.17.2)
kubectl api-resource
kind
どのオブジェクトであるかを設定します。
今回であればkind: Pod
を指定しているため、
Podオブジェクト
が作成されます。metadata
このオブジェクトのメタ情報を設定します。
name: 任意の命名(後に他のkindオブジェクトで指定される値)
labels: 任意の命名が可能(但し制限もあるため、公式を参考に)
spec
オブジェクトの仕様を表します。
- containers
- name
Pod名- image
使用するコンテナイメージ名- resources
CPU/メモリ等を設定- ports
- containerPort
コンテナ内からExposeされるポート番号デプロイ方法
kubectl apply pod.yaml
- 投稿日:2020-02-17T16:31:42+09:00
Dockerの自動起動設定を外す
- 投稿日:2020-02-17T13:26:04+09:00
DockerのBuild Cacheの削除
Dockerfileのbuildをしていると
no space left
なるエラーが発生してしまいました。
docker system df
でDockerが使っているストレージ容量を確認したところBuild cacheがやたらに大きいことが判明。$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 25 6 99.35GB 74.17GB (74%) Containers 8 6 27.06GB 6.004GB (22%) Local Volumes 3 1 0B 0B Build Cache 214 0 41.58GB 41.58GBこのBuild cahcheのクリア方法がすぐに分からなかったのでメモとして残しておきます。
結論としては非常に簡単で、次のコマンドで消せます(参考URL)。$ docker builder prune
このコマンド実行後、
docker system df
をしてみると...$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 25 6 99.35GB 74.17GB (74%) Containers 8 6 27.06GB 6.004GB (22%) Local Volumes 3 1 0B 0B Build Cache 96 0 0B 0B無事に消せました。
Dockerを使っていてストレージの残り容量に困っている方は試してみる価値があるのではないでしょうか。
- 投稿日:2020-02-17T12:07:47+09:00
邪悪なDocker for Macを捨てて最速のDocker環境を手に入れる
Macでネイティブでの動作とほぼ同等の速度のDockerを手に入れることができたので、その知見について公開します。
ものによりますが、最大10倍程度パフォーマンスの向上が見られました。
※タイトルには若干誇張が含まれていますDocker for Macは遅い
MacでDockerを使って開発している方は体感していると思うのですが、Docker for Macの速度はネイティブで動かすのと比べて相当遅く、リソースも消費します。
自分はRails + React(webpack) というWebでは比較的一般的なスタックで開発しているのですが、Railsの初期読み込み・webpackの(差分)トランスパイル・yarn installなどが致命的に重く、LinuxでのDocker環境と比較してかなりDXが低下します。
特に大量のファイルの読み込みや、ファイル変更のリアルタイム検知が弱い印象が強いです。また、Docker for Macは不安定な面もあり、(例えばgitのブランチ変更などで)大量のファイル変更が起こった場合にCPU使用率が100%に張り付いてしまい、再起動しないと戻ってこないなどの現象も起きることがあります。
com.docker.hyperkit 100% cpu usage is back again · Issue #3499 · docker/for-macこの問題の大部分は調べた限りファイルシステムをマウントした際のオーバーヘッドに起因しており、docker-syncなどを使ってファイルシステムの扱い方を変えることである程度改善することなどが知られています。
しかし、docker-syncも不安定さが残るなど、懸念点があります。
参考: hanhan's blog - Docker for Macのmount遅い問題まとめまた、自分は設定の煩雑さから使ったことがないのですが、Docker for MacはNFS Volume sharingに対応しているので、それを使うことでもある程度改善されるのではないかと思います。
この記事ではパフォーマンス低下の最も大きな原因となっているファイルシステムについていくつか改善案を試し、その中で最も効果があったVirtualBox(Ubuntu)を使い、ファイルシステムのマウントを行わずに(VMのネイティブ?ファイルシステム上で)Dockerを使う、という手法について解説しようと思います。
Docker for Macと今回構築する環境(VirtualBox + Docker)の違い
基本的にはどちらもVM上でDockerが動作することになります。
Docker for Mac
Docker for Macでは、インストール時にAlphine LinuxベースのHyperkit VMがインストールされ、起動時に
/var/run/docker.sock
が生成されます。
このVMはDocker for Mac上で自動的に管理され、Mac上でdocker
,docker-compose
コマンドを実行する際に特に設定をしていない限りdocker.sock
を経由して透過的にVM内でDockerコマンドが実行されるようになっています。VirtualBox + Docker
一方、今回構築する環境ではVirtualBoxを使って実際にVMを管理することになります。
Vagrantを用いてVirtualBoxでUbuntu環境を構築し、その中でDockerを動作させます。
完全に独立した環境のため、ファイルシステムについては VMに設定しているものがDocker上にマウントされ 、Dockerコマンドについてはsshで接続した上でVM内から実行することになります。
VM内のdocker.sock
をMacにマウントすることでMac上から透過的にDockerコマンドを扱えるかもしれませんが、まだ検証していません。ファイルシステムについてですが、Vagrantでファイルを同期する
sync_folder
機能で指定できる同期タイプとして
- VirtualBox(オプション指定なし)
- NFS
- rsync
- SMB
があります。
しかし、今回はどれも使わずに(VM起動時に1度だけrsyncをする)、Vagrantから独立した手段でファイル同期を行います。実際の速度差
Docker for Mac, VirtualBox + Docker, Macネイティブについて、計測が容易で差が大きかったものについて環境毎の実測値を記載します。
Command Docker for Mac VirtualBox + Docker Macネイティブ 差 yarn install 117.84s 117.84s 16.88s 6.8倍高速化 Rails起動後の初回アクセス
(curl)22.43s 2.199s 3.32s 10倍高速化 VMの設定や使い方
VMの構築・設定
Vagrantを使ってVMを構築します。
実際に使っているVagrantfileの構成は以下です。
CPU・メモリ・ディスクサイズなどは適宜調整してください。追加でプラグインとして
- vagrant-disksize
- vagrant-hostsupdater
- vagrant-mutagen
が必要になるので、
$ vagrant plugin install vagrant-disksize vagrant-hostsupdater vagrant-mutagen
を実行してプラグインをインストールしておいてください。Vagrant.configure('2') do |config| config.vm.box = 'ubuntu/xenial64' config.vm.hostname = 'my-app' config.vm.network :private_network, ip: '192.168.50.10' config.vm.provider :virtualbox do |vb| vb.gui = false vb.cpus = 4 vb.memory = 8192 vb.customize ['modifyvm', :id, '--natdnsproxy1', 'off'] vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'off'] end config.disksize.size = '30GB' config.mutagen.orchestrate = true config.vm.synced_folder './', '/home/vagrant/app', type: "rsync", rsync_auto: true, rsync__exclude: ['.git/', 'node_modules/', 'log/', 'tmp/'] config.vm.provision 'shell', inline: <<-SHELL curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh usermod -aG docker vagrant curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose SHELL endVMの使い方
(実際のコマンドの実行はファイル同期の章に書いている内容を行った後にしてください。)
$ vagrant up
を実行すると各設定が適用されたVMの作成・起動とrsyncの実行が行われ、./
が/home/vagrant/app
に同期されます。rsyncの実行は起動時のみで自動的な実行は行われません。
初回はprovisionでDockerとDocker Composeのインストールが行われます。その後、
$ vagrant ssh
をしてVMにSSHでログインし、$ cd app && docker-compose up {rails}
のようなコマンドを実行することでDockerコンテナが立ち上がります。
イメージのビルドなどの処理は必要に応じて適宜行ってください。
立ち上がったアプリケーションにはVagrantfileで指定しているIPでアクセスできます。 (http://192.168.50.10:{3000}
など)ファイル同期の手段
開発を行う際にはローカルとVM上でファイルを同期する必要がありますが、その際にVirtualBoxの標準の共有フォルダやNFSを使うと、VM内からDockerへマウントした際のパフォーマンスが結局大幅に低下します。
そのため、MacからVMへのファイルシステム自体のマウントは行わず、ファイル変更を検知して相互にファイルを転送するような同期手段が望ましいです。Vagrantのrsyncでの同期がそれに近いのですが、その場合ホストからVMへ単方向の同期しか行われないという問題があります。
具体的にはVM内で$ bundle install
や$ yarn install
を実行した際に更新されるGemfile.lock
やyarn.lock
のようなファイルについてVMからMacへ同期が行われません。VM内のファイル変更を検知してホストにrsyncを実行するようなコマンド実行も試したのですが、双方向にrsyncで適切な同期を行うというのは実現できませんでした。
ファイル同期のソリューション 「Mutagen」
上記の問題についてですが、最終的にMutagenを使うことで解決しました。
VMの構築・設定の節で既に記載しているのですが、Mutagenをインストールし、vagrant-mutagen
プラグインを導入することで双方向のファイル同期が適切に行われます。
Mutagenのインストールですが、Macでは$ brew install mutagen-io/mutagen/mutagen
を実行することで行う事ができます。その後、Vagrantfileと同じ階層に以下の
mutagen.yml
を配置してください。sync: app: mode: "two-way-resolved" alpha: "./" beta: "{my-app (Vagrantfileで指定したホスト名)}:/home/vagrant/app" ignore: vcs: true paths: - "/node_modules" - "/log" - "/tmp"その後
$ vagrant up
でVMを起動すると、Mutagenによって双方向のファイル同期が行われます。
この同期は双方向にほぼリアルタイムで行われ、ファイルシステムのマウントではなくファイルの転送で実現されているため、最終的にDockerコンテナへマウントされた際のオーバーヘッドはほぼ発生しません。結果
結果として現在業務で行っている開発にVagrantとMutagenを導入したことで、Macでも快適にDockerを使った開発が行えるようになりました。
Docker for Macでは速度・リソース・安定性のどの面でも苦労していたのですが、現在はある程度安定したDocker環境を構築できています。
sshしなければ使えないなど多少不便な点も残ってはいるのですが、それを上回るメリットが享受できていると感じています。Docker for Macでの開発に消耗している方は数多くいる印象なので、もし機会があればこの構成を試してみていただけると幸いです。
備考・注意点
実行環境のスペック
MacBook Pro (16-inch, 2019)
CPU: 2.4GHz 8コア Intel Core i9
メモリ: 64GB 2667MHz DDR4Docker for MacへのMutagenの適用
MutagenはDocker for Macで扱うこともできるようです。
その際のパフォーマンスは計測できていないのですが、もしかしたらVagrantを経由した場合と同等の速度が出るかもしれません。今回はMutagen導入時には既にVagrant + rsyncを使った場合の速度が非常に速いことが確認できていたので、設定がシンプルだったvagrant-mutagenを採用したのですが、Docker for Mac + Mutagenでの開発も調査する価値があるかと思います。
マイクロサービス開発への対応
場合によっては複数のリポジトリに横断するマイクロサービス開発をDockerのnetwork機能を用いて行っている場合があるかと思います。
この構成ではリポジトリ毎に完全に独立したVMが作成されるという特性上、Docker networkを使った開発が難しくなってしまう可能性があります。現在マイクロサービスでの開発は行っていないため確認できていないのですが、解決策として
- 上記Docker for MacへのMutagenの適用
- 必要なマイクロサービスをsubtree(submodule)として配置したリポジトリを作り、そのリポジトリ上でVMを構築する
というものが使えないかと考えています。
これについては今後マイクロサービス開発が必要になったタイミングで検証を進めていこうかと考えています。Mutagenの同期セッションについて
vagrant-mutagenでのファイル同期についてですが、
$ vagrant halt
を行わずにVMが終了した場合にはセッションが削除されずに残ってしまうという問題が確認できています。
セッションが残っていた場合には次回のVM起動時にセッションが新たに作成され、多重にセッションが貼られたまま残り続けるという状態になってしまいます。
また、残っているセッションはmutagen.yml
の設定を読み込まずに古い設定のまま動作し続けるためバグの原因となります(なりました)。MacのクラッシュやVMの正常な終了が行えなかった際には
$ mutagen sync list
でセッションを確認し、不要なセッションについては$ mutagen sync terminate {session_id}
で削除するようにしてください。docker-composeの設定について
docker-compose.yml
に以下のようにgem用、npm用のvolumeを作成しているのですが、設定に不備があってDocker for Macでパフォーマンスが落ちているなどあればコメントをいただけると助かります。services: rails: &app_base volumes: - .:/usr/src/app:cached - bundle:/usr/local/bundle:cached frontend: volumes: - .:/usr/src/app:cached - npm:/usr/local/npm:cached volumes: bundle: npm:
- 投稿日:2020-02-17T12:07:47+09:00
邪悪なDocker for Macを捨ててMac最速のDocker環境を手に入れる
Macでネイティブでの動作とほぼ同等の速度のDockerを手に入れることができたので、その知見について公開します。
ものによりますが、最大10倍程度パフォーマンスの向上が見られました。
※タイトルには若干誇張が含まれていますDocker for Macは遅い
MacでDockerを使って開発している方は体感していると思うのですが、Docker for Macの速度はネイティブで動かすのと比べて相当遅く、リソースも消費します。
自分はRails + React(webpack) というWebでは比較的一般的なスタックで開発しているのですが、Railsの初期読み込み・webpackの(差分)トランスパイル・yarn installなどが致命的に重く、LinuxでのDocker環境と比較してかなりDXが低下します。
特に大量のファイルの読み込みや、ファイル変更のリアルタイム検知が弱い印象が強いです。また、Docker for Macは不安定な面もあり、(例えばgitのブランチ変更などで)大量のファイル変更が起こった場合にCPU使用率が100%に張り付いてしまい、再起動しないと戻ってこないなどの現象も起きることがあります。
com.docker.hyperkit 100% cpu usage is back again · Issue #3499 · docker/for-macこの問題の大部分は調べた限りファイルシステムをマウントした際のオーバーヘッドに起因しており、docker-syncなどを使ってファイルシステムの扱い方を変えることである程度改善することなどが知られています。
しかし、docker-syncも不安定さが残るなど、懸念点があります。
参考: hanhan's blog - Docker for Macのmount遅い問題まとめまた、自分は設定の煩雑さから使ったことがないのですが、Docker for MacはNFS Volume sharingに対応しているので、それを使うことでもある程度改善されるのではないかと思います。
この記事ではパフォーマンス低下の最も大きな原因となっているファイルシステムについていくつか改善案を試し、その中で最も効果があったVirtualBox(Ubuntu)を使い、ファイルシステムのマウントを行わずに(VMのネイティブ?ファイルシステム上で)Dockerを使う、という手法について解説しようと思います。
Docker for Macと今回構築する環境(VirtualBox + Docker)の違い
基本的にはどちらもVM上でDockerが動作することになります。
Docker for Mac
Docker for Macでは、インストール時にAlphine LinuxベースのHyperkit VMがインストールされ、起動時に
/var/run/docker.sock
が生成されます。
このVMはDocker for Mac上で自動的に管理され、Mac上でdocker
,docker-compose
コマンドを実行する際に特に設定をしていない限りdocker.sock
を経由して透過的にVM内でDockerコマンドが実行されるようになっています。VirtualBox + Docker
一方、今回構築する環境ではVirtualBoxを使って実際にVMを管理することになります。
Vagrantを用いてVirtualBoxでUbuntu環境を構築し、その中でDockerを動作させます。
完全に独立した環境のため、ファイルシステムについては VMに設定しているものがDocker上にマウントされ 、Dockerコマンドについてはsshで接続した上でVM内から実行することになります。
VM内のdocker.sock
をMacにマウントすることでMac上から透過的にDockerコマンドを扱えるかもしれませんが、まだ検証していません。ファイルシステムについてですが、Vagrantでファイルを同期する
sync_folder
機能で指定できる同期タイプとして
- VirtualBox(オプション指定なし)
- NFS
- rsync
- SMB
があります。
しかし、今回はどれも使わずに(VM起動時に1度だけrsyncをする)、Vagrantから独立した手段でファイル同期を行います。実際の速度差
Docker for Mac, VirtualBox + Docker, Macネイティブについて、計測が容易で差が大きかったものについて環境毎の実測値を記載します。
Command Docker for Mac VirtualBox + Docker Macネイティブ 差 yarn install 117.84s 16.86s 16.88s 6.8倍高速化 Rails起動後の初回アクセス
(curl)22.43s 2.199s 3.32s 10倍高速化 VMの設定や使い方
VMの構築・設定
Vagrantを使ってVMを構築します。
実際に使っているVagrantfileの構成は以下です。
CPU・メモリ・ディスクサイズなどは適宜調整してください。追加でプラグインとして
- vagrant-disksize
- vagrant-hostsupdater
- vagrant-mutagen
が必要になるので、
$ vagrant plugin install vagrant-disksize vagrant-hostsupdater vagrant-mutagen
を実行してプラグインをインストールしておいてください。Vagrant.configure('2') do |config| config.vm.box = 'ubuntu/xenial64' config.vm.hostname = 'my-app' config.vm.network :private_network, ip: '192.168.50.10' config.vm.provider :virtualbox do |vb| vb.gui = false vb.cpus = 4 vb.memory = 8192 vb.customize ['modifyvm', :id, '--natdnsproxy1', 'off'] vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'off'] end config.disksize.size = '30GB' config.mutagen.orchestrate = true config.vm.synced_folder './', '/home/vagrant/app', type: "rsync", rsync_auto: true, rsync__exclude: ['.git/', 'node_modules/', 'log/', 'tmp/'] config.vm.provision 'shell', inline: <<-SHELL curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh usermod -aG docker vagrant curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose SHELL endVMの使い方
(実際のコマンドの実行はファイル同期の章に書いている内容を行った後にしてください。)
$ vagrant up
を実行すると各設定が適用されたVMの作成・起動とrsyncの実行が行われ、./
が/home/vagrant/app
に同期されます。rsyncの実行は起動時のみで自動的な実行は行われません。
初回はprovisionでDockerとDocker Composeのインストールが行われます。その後、
$ vagrant ssh
をしてVMにSSHでログインし、$ cd app && docker-compose up {rails}
のようなコマンドを実行することでDockerコンテナが立ち上がります。
イメージのビルドなどの処理は必要に応じて適宜行ってください。
立ち上がったアプリケーションにはVagrantfileで指定しているIPでアクセスできます。 (http://192.168.50.10:{3000}
など)ファイル同期の手段
開発を行う際にはローカルとVM上でファイルを同期する必要がありますが、その際にVirtualBoxの標準の共有フォルダやNFSを使うと、VM内からDockerへマウントした際のパフォーマンスが結局大幅に低下します。
そのため、MacからVMへのファイルシステム自体のマウントは行わず、ファイル変更を検知して相互にファイルを転送するような同期手段が望ましいです。Vagrantのrsyncでの同期がそれに近いのですが、その場合ホストからVMへ単方向の同期しか行われないという問題があります。
具体的にはVM内で$ bundle install
や$ yarn install
を実行した際に更新されるGemfile.lock
やyarn.lock
のようなファイルについてVMからMacへ同期が行われません。VM内のファイル変更を検知してホストにrsyncを実行するようなコマンド実行も試したのですが、双方向にrsyncで適切な同期を行うというのは実現できませんでした。
ファイル同期のソリューション 「Mutagen」
上記の問題についてですが、最終的にMutagenを使うことで解決しました。
VMの構築・設定の節で既に記載しているのですが、Mutagenをインストールし、vagrant-mutagen
プラグインを導入することで双方向のファイル同期が適切に行われます。
Mutagenのインストールですが、Macでは$ brew install mutagen-io/mutagen/mutagen
を実行することで行う事ができます。その後、Vagrantfileと同じ階層に以下の
mutagen.yml
を配置してください。sync: app: mode: "two-way-resolved" alpha: "./" beta: "{my-app (Vagrantfileで指定したホスト名)}:/home/vagrant/app" ignore: vcs: true paths: - "/node_modules" - "/log" - "/tmp"その後
$ vagrant up
でVMを起動すると、Mutagenによって双方向のファイル同期が行われます。
この同期は双方向にほぼリアルタイムで行われ、ファイルシステムのマウントではなくファイルの転送で実現されているため、最終的にDockerコンテナへマウントされた際のオーバーヘッドはほぼ発生しません。結果
結果として現在業務で行っている開発にVagrantとMutagenを導入したことで、Macでも快適にDockerを使った開発が行えるようになりました。
Docker for Macでは速度・リソース・安定性のどの面でも苦労していたのですが、現在はある程度安定したDocker環境を構築できています。
sshしなければ使えないなど多少不便な点も残ってはいるのですが、それを上回るメリットが享受できていると感じています。Docker for Macでの開発に消耗している方は数多くいる印象なので、もし機会があればこの構成を試してみていただけると幸いです。
備考・注意点
実行環境のスペック
MacBook Pro (16-inch, 2019)
CPU: 2.4GHz 8コア Intel Core i9
メモリ: 64GB 2667MHz DDR4Docker for MacへのMutagenの適用
MutagenはDocker for Macで扱うこともできるようです。
その際のパフォーマンスは計測できていないのですが、もしかしたらVagrantを経由した場合と同等の速度が出るかもしれません。今回はMutagen導入時には既にVagrant + rsyncを使った場合の速度が非常に速いことが確認できていたので、設定がシンプルだったvagrant-mutagenを採用したのですが、Docker for Mac + Mutagenでの開発も調査する価値があるかと思います。
マイクロサービス開発への対応
場合によっては複数のリポジトリに横断するマイクロサービス開発をDockerのnetwork機能を用いて行っている場合があるかと思います。
この構成ではリポジトリ毎に完全に独立したVMが作成されるという特性上、Docker networkを使った開発が難しくなってしまう可能性があります。現在マイクロサービスでの開発は行っていないため確認できていないのですが、解決策として
- 上記Docker for MacへのMutagenの適用
- 必要なマイクロサービスをsubtree(submodule)として配置したリポジトリを作り、そのリポジトリ上でVMを構築する
というものが使えないかと考えています。
これについては今後マイクロサービス開発が必要になったタイミングで検証を進めていこうかと考えています。Mutagenの同期セッションについて
vagrant-mutagenでのファイル同期についてですが、
$ vagrant halt
を行わずにVMが終了した場合にはセッションが削除されずに残ってしまうという問題が確認できています。
セッションが残っていた場合には次回のVM起動時にセッションが新たに作成され、多重にセッションが貼られたまま残り続けるという状態になってしまいます。
また、残っているセッションはmutagen.yml
の設定を読み込まずに古い設定のまま動作し続けるためバグの原因となります(なりました)。MacのクラッシュやVMの正常な終了が行えなかった際には
$ mutagen sync list
でセッションを確認し、不要なセッションについては$ mutagen sync terminate {session_id}
で削除するようにしてください。docker-composeの設定について
docker-compose.yml
に以下のようにgem用、npm用のvolumeを作成しているのですが、設定に不備があってDocker for Macでパフォーマンスが落ちているなどあればコメントをいただけると助かります。services: rails: &app_base volumes: - .:/usr/src/app:cached - bundle:/usr/local/bundle:cached frontend: volumes: - .:/usr/src/app:cached - npm:/usr/local/npm:cached volumes: bundle: npm:
- 投稿日:2020-02-17T12:07:47+09:00
DXを大幅に低下させるDocker for Macを捨ててMac最速のDocker環境を手に入れる
※DXはデジタルトランスフォーメーションではなくてDeveloper Experienceの方です
Macでネイティブでの動作とほぼ同等の速度の安定したDocker環境を手に入れることができたので、その知見について公開します。
ものによりますが、最大10倍程度パフォーマンスの向上が見られました。Docker for Macは遅い
MacでDockerを使って開発している方は体感していると思うのですが、Docker for Macの速度はネイティブで動かすのと比べて相当遅く、リソースも消費します。
自分はRails + React(webpack) というWebでは比較的一般的なスタックで開発しているのですが、Railsの初期読み込み・webpackの(差分)トランスパイル・yarn installなどが致命的に重く、LinuxでのDocker環境と比較してかなりDXが低下します。
特に大量のファイルの読み込みや、ファイル変更のリアルタイム検知が弱い印象が強いです。また、Docker for Macは不安定な面もあり、(例えばgitのブランチ変更などで)大量のファイル変更が起こった場合にCPU使用率が100%に張り付いてしまい、再起動しないと戻ってこないなどの現象も起きることがあります。
com.docker.hyperkit 100% cpu usage is back again · Issue #3499 · docker/for-macこの問題の大部分は調べた限りファイルシステムをマウントした際のオーバーヘッドに起因しており、docker-syncなどを使ってファイルシステムの扱い方を変えることである程度改善することが知られています。
しかし、docker-syncも不安定さが残るなど、懸念点があります。
参考: hanhan's blog - Docker for Macのmount遅い問題まとめまた、自分は設定の煩雑さから使ったことがないのですが、Docker for MacはNFS Volume sharingに対応しているので、それを使うことでもある程度改善されるのではないかと思います。
この記事ではパフォーマンス低下の最も大きな原因となっているファイルシステムについていくつか改善案を試し、その中で最も効果があったVirtualBox(Ubuntu)を使い、ファイルシステムのマウントを行わずに(VMのネイティブ?ファイルシステム上で)Dockerを使う、という手法について解説しようと思います。
Docker for Macと今回構築する環境(VirtualBox + Docker)の違い
基本的にはどちらもVM上でDockerが動作することになります。
Docker for Mac
Docker for Macでは、インストール時にAlpine LinuxベースのHyperkit VMがインストールされ、起動時に
/var/run/docker.sock
が生成されます。
このVMはDocker for Mac上で自動的に管理され、Mac上でdocker
,docker-compose
コマンドを実行する際に特に設定をしていない限りdocker.sock
を経由して透過的にVM内でDockerコマンドが実行されるようになっています。VirtualBox + Docker
一方、今回構築する環境ではVirtualBoxを使って実際にVMを管理することになります。
Vagrantを用いてVirtualBoxでUbuntu環境を構築し、その中でDockerを動作させます。
完全に独立した環境のため、ファイルシステムについては VMに設定しているものがDocker上にマウントされ 、Dockerコマンドについてはsshで接続した上でVM内から実行することになります。
VM内のdocker.sock
をMacにマウントすることでMac上から透過的にDockerコマンドを扱えるかもしれませんが、まだ検証していません。ファイルシステムについてですが、Vagrantでファイルを同期する
sync_folder
機能で指定できる同期タイプとして
- VirtualBox(オプション指定なし)
- NFS
- rsync
- SMB
があります。
しかし、今回はどれも使わずに(VM起動時に1度だけrsyncをする)、Vagrantから独立した手段でファイル同期を行います。実際の速度差
Docker for Mac, VirtualBox + Docker, Macネイティブについて、計測が容易で差が大きかったものについて環境毎の実測値を記載します。
Railsへのアクセスについて、ネイティブよりVMの方が早い理由についてはよく分かっていません。
Command Docker for Mac VirtualBox + Docker Macネイティブ 差 yarn install 117.84s 16.86s 16.88s 6.8倍高速化 Rails起動後の初回アクセス
(curl)22.43s 2.199s 3.32s 10倍高速化 VMの設定や使い方
VMの構築・設定
Vagrantを使ってVMを構築します。
実際に使っているVagrantfileの構成は以下です。
CPU・メモリ・ディスクサイズなどは適宜調整してください。追加でプラグインとして
- vagrant-disksize
- vagrant-hostsupdater
- vagrant-mutagen
が必要になるので、
$ vagrant plugin install vagrant-disksize vagrant-hostsupdater vagrant-mutagen
を実行してプラグインをインストールしておいてください。Vagrant.configure('2') do |config| config.vm.box = 'ubuntu/xenial64' config.vm.hostname = 'my-app' config.vm.network :private_network, ip: '192.168.50.10' config.vm.provider :virtualbox do |vb| vb.gui = false vb.cpus = 4 vb.memory = 8192 vb.customize ['modifyvm', :id, '--natdnsproxy1', 'off'] vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'off'] end config.disksize.size = '30GB' config.mutagen.orchestrate = true config.vm.synced_folder './', '/home/vagrant/app', type: "rsync", rsync_auto: true, rsync__exclude: ['.git/', 'node_modules/', 'log/', 'tmp/'] config.vm.provision 'shell', inline: <<-SHELL curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh usermod -aG docker vagrant curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose SHELL endVMの使い方
(実際のコマンドの実行はファイル同期の章に書いている内容を行った後にしてください。)
$ vagrant up
を実行すると各設定が適用されたVMの作成・起動とrsyncの実行が行われ、./
が/home/vagrant/app
に同期されます。rsyncの実行は起動時のみで自動的な実行は行われません。
初回はprovisionでDockerとDocker Composeのインストールが行われます。その後、
$ vagrant ssh
をしてVMにSSHでログインし、$ cd app && docker-compose up {rails}
のようなコマンドを実行することでDockerコンテナが立ち上がります。
イメージのビルドなどの処理は必要に応じて適宜行ってください。
立ち上がったアプリケーションにはVagrantfileで指定しているIPでアクセスできます。 (http://192.168.50.10:{3000}
など)ファイル同期の手段
開発を行う際にはローカルとVM上でファイルを同期する必要がありますが、その際にVirtualBoxの標準の共有フォルダやNFSを使うと、VM内からDockerへマウントした際のパフォーマンスが結局大幅に低下します。
そのため、MacからVMへのファイルシステム自体のマウントは行わず、ファイル変更を検知して相互にファイルを転送するような同期手段が望ましいです。Vagrantのrsyncでの同期がそれに近いのですが、その場合ホストからVMへ単方向の同期しか行われないという問題があります。
具体的にはVM内で$ bundle install
や$ yarn install
を実行した際に更新されるGemfile.lock
やyarn.lock
のようなファイルについてVMからMacへ同期が行われません。VM内のファイル変更を検知してホストにrsyncを実行するようなコマンド実行も試したのですが、双方向にrsyncで適切な同期を行うというのは実現できませんでした。
ファイル同期のソリューション 「Mutagen」
上記の問題についてですが、最終的にMutagenを使うことで解決しました。
今回Vagrantを採用している理由の一つとして、Vagrant PluginでVMに対してMutagenの設定が簡単に行える、というものもあります。
VMの構築・設定の節で既に記載しているのですが、Mutagenをインストールし、vagrant-mutagen
プラグインを導入することで双方向のファイル同期が適切に行われます。
Mutagenのインストールですが、Macでは$ brew install mutagen-io/mutagen/mutagen
を実行することで行う事ができます。その後、Vagrantfileと同じ階層に以下の
mutagen.yml
を配置してください。sync: app: mode: "two-way-resolved" alpha: "./" beta: "{my-app (Vagrantfileで指定したホスト名)}:/home/vagrant/app" ignore: vcs: true paths: - "/node_modules" - "/log" - "/tmp"その後
$ vagrant up
でVMを起動すると、Mutagenによって双方向のファイル同期が行われます。
この同期は双方向にほぼリアルタイムで行われ、ファイルシステムのマウントではなくファイルの転送で実現されているため、最終的にDockerコンテナへマウントされた際のオーバーヘッドはほぼ発生しません。結果
結果として現在業務で行っている開発にVagrantとMutagenを導入したことで、Macでも快適にDockerを使った開発が行えるようになりました。
Docker for Macでは速度・リソース・安定性のどの面でも苦労していたのですが、現在はある程度安定したDocker環境を構築できています。
sshしなければ使えないなど多少不便な点も残ってはいるのですが、それを上回るメリットが享受できていると感じています。Docker for Macでの開発に消耗している方は数多くいる印象なので、もし機会があればこの構成を試してみていただけると幸いです。
備考・注意点
実行環境のスペック
MacBook Pro (16-inch, 2019)
CPU: 2.4GHz 8コア Intel Core i9
メモリ: 64GB 2667MHz DDR4Docker for MacへのMutagenの適用
MutagenはDocker for Macで扱うこともできるようです。
その際のパフォーマンスは計測できていないのですが、もしかしたらVagrantを経由した場合と同等の速度が出るかもしれません。今回はMutagen導入時には既にVagrant + rsyncを使った場合の速度が非常に速いことが確認できていたので、設定がシンプルだったvagrant-mutagenを採用したのですが、Docker for Mac + Mutagenでの開発も調査する価値があるかと思います。
マイクロサービス開発への対応
場合によっては複数のリポジトリに横断するマイクロサービス開発をDockerのnetwork機能を用いて行っている場合があるかと思います。
この構成ではリポジトリ毎に完全に独立したVMが作成されるという特性上、Docker networkを使った開発が難しくなってしまう可能性があります。現在マイクロサービスでの開発は行っていないため確認できていないのですが、解決策として
- 上記Docker for MacへのMutagenの適用
- 必要なマイクロサービスをsubtree(submodule)として配置したリポジトリを作り、そのリポジトリ上でVMを構築する
というものが使えないかと考えています。
これについては今後マイクロサービス開発が必要になったタイミングで検証を進めていこうかと考えています。Mutagenの同期セッションについて
vagrant-mutagenでのファイル同期についてですが、
$ vagrant halt
を行わずにVMが終了した場合にはセッションが削除されずに残ってしまうという問題が確認できています。
セッションが残っていた場合には次回のVM起動時にセッションが新たに作成され、多重にセッションが貼られたまま残り続けるという状態になってしまいます。
また、残っているセッションはmutagen.yml
の設定を読み込まずに古い設定のまま動作し続けるためバグの原因となります(なりました)。MacのクラッシュやVMの正常な終了が行えなかった際には
$ mutagen sync list
でセッションを確認し、不要なセッションについては$ mutagen sync terminate {session_id}
で削除するようにしてください。docker-composeの設定について
docker-compose.yml
に以下のようにgem用、npm用のvolumeを作成しているのですが、設定に不備があってDocker for Macでパフォーマンスが落ちているなどあればコメントをいただけると助かります。services: rails: volumes: - .:/usr/src/app:cached - bundle:/usr/local/bundle:cached frontend: volumes: - .:/usr/src/app:cached - yarn:/usr/local/yarn:cached volumes: bundle: yarn:
- 投稿日:2020-02-17T11:38:43+09:00
コンテナ内でfluentd実行したら"unexpected error error_class=Errno::EADDRINUSE"でエラッた話
はじめに
書いた記事の続き?にあたるもの
https://qiita.com/arata-honda/items/03d6da7c9f84f67466a9エラー内容
2020-02-17 11:21:26 +0900 [error]: #0 suppressed same stacktrace 2020-02-17 11:21:26 +0900 [info]: Worker 0 finished unexpectedly with status 1 2020-02-17 11:21:26 +0900 [info]: adding match in @mainstream pattern="docker.**" type="file" 2020-02-17 11:21:26 +0900 [warn]: #0 [output_docker1] 'time_format' specified without 'time_key', will be ignored 2020-02-17 11:21:26 +0900 [info]: adding match in @mainstream pattern="**" type="file" 2020-02-17 11:21:26 +0900 [warn]: #0 [output1] 'time_format' specified without 'time_key', will be ignored 2020-02-17 11:21:26 +0900 [info]: adding filter pattern="**" type="stdout" 2020-02-17 11:21:26 +0900 [info]: adding source type="forward" 2020-02-17 11:21:26 +0900 [warn]: #0 define <match fluent.**> to capture fluentd logs in top level is deprecated. Use <label @FLUENT_LOG> instead 2020-02-17 11:21:26 +0900 [info]: #0 starting fluentd worker pid=204 ppid=34 worker=0 2020-02-17 11:21:26 +0900 [info]: #0 [input1] listening port port=24224 bind="0.0.0.0" 2020-02-17 11:21:26 +0900 [error]: #0 unexpected error error_class=Errno::EADDRINUSE error="Address in use - bind(2) for 0.0.0.0:24224" 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/2.5.0/socket.rb:201:in `bind' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/2.5.0/socket.rb:201:in `listen' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/plugin_helper/server.rb:355:in `server_create_tcp_socket' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/plugin_helper/server.rb:212:in `server_create_for_tcp_connection' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/plugin_helper/server.rb:92:in `server_create_connection' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/plugin/in_forward.rb:172:in `start' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/root_agent.rb:200:in `block in start' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/root_agent.rb:189:in `block (2 levels) in lifecycle' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/root_agent.rb:188:in `each' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/root_agent.rb:188:in `block in lifecycle' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/root_agent.rb:175:in `each' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/root_agent.rb:175:in `lifecycle' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/root_agent.rb:199:in `start' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/engine.rb:248:in `start' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/engine.rb:147:in `run' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/supervisor.rb:592:in `block in run_worker' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/supervisor.rb:823:in `main_process' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/supervisor.rb:586:in `run_worker' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/lib/fluent/command/fluentd.rb:338:in `<top (required)>' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/lib/ruby/gems/2.5.0/gems/fluentd-1.9.2/bin/fluentd:8:in `<top (required)>' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/bin/fluentd:23:in `load' 2020-02-17 11:21:26 +0900 [error]: #0 /usr/bin/fluentd:23:in `<main>' 2020-02-17 11:21:26 +0900 [error]: #0 unexpected error error_class=Errno::EADDRINUSE error="Address in use - bind(2) for 0.0.0.0:24224"エラー原因
ここら辺に近しい
psすると/ # ps PID USER TIME COMMAND 1 root 0:00 tini -- /bin/entrypoint.sh fluentd 6 root 0:00 {fluentd} /usr/bin/ruby /usr/bin/fluentd -c /fluentd/etc/fluent.conf -p /fluentd/plugins 20 root 0:00 /usr/bin/ruby -Eascii-8bit:ascii-8bit /usr/bin/fluentd -c /fluentd/etc/fluent.conf -p /fluentd/pl 29 root 0:00 /bin/sh 288 root 0:00 psすでにfluentdのプロセスがexecした時に起動されていてポート24224が使用されていたため
unexpected error error_class=Errno::EADDRINUSE error="Address in use - bind(2) for 0.0.0.0:24224"
のエラーがいっぱいでました。
- 投稿日:2020-02-17T10:58:35+09:00
[Docker] "Timed out waiting for the lifecycle-server to start"によりサービスが起動しない
Docker Desktopが2.2系にアップデートされて以降、表題のエラーが通知され起動しなくなった。
軽く調べたところ、docker/
for-win のIssue#4393がヒットし、読み進めていくと、rezapci commented on 15 Oct 2019にて提示された方法でエラーは出なくなった。しかし、次いで Error response from daemon: open \.\pipe\docker_engine_linux のエラーが表示される。
これは、表示されたエラーダイアログにて、Factory Defaultsのボタンを押して再起動することで、最終的には起動が確認できた。
- 投稿日:2020-02-17T06:25:26+09:00
Dockerのbridge接続の通信フローをnftablesで追う
はじめに
いまさらながらCentOS8でDockerを勉強しはじめました。で、外部ホスト<--->コンテナのパケットの流れを追ってみたくていろいろ調べました。
けど、リクエストは流れが追えたのですが、レスポンスが追えていません。。。
ひとまずリクエストの経路だけまとめます。いろいろ前提条件
検証環境
以下の環境でトレースしています。
- CentOS8(8.1.1911)
- Docker(19.03.5)
- firewalld(0.7.0)
- iptables(1.8.2:nf_tables)
- nftables(0.9.0)
Docker動作環境
userland proxy(docker-proxy)
iptables / nftables によるdockerネットワークの基本的な動作をみたかったので、docker-pxoryを利用していません。(ヘアピンNAT)
以下のファイルを配置して検証しています。/etc/docker/daemon.json{ "userland-proxy": false }docker network and containers
検証環境として、以下のエントリで生成されたものを利用します。
CentOS8で構成したdockerホスト10.254.10.252
、説明はradiusを対象にしていきます。Docker Composeでネットワークサービス群を5分で作れるようにした(dhcp/radius/proxy/tftp/syslog)
以下のコンテナが生成されます。
server app address listen proxy squid 172.20.0.2 8080/tcp syslog rsyslog 172.20.0.3 514/udp radius freeRADIUS 172.20.0.4 1812/udp dhcp ISC-Kea 172.20.0.5 67/udp tftp tftp-server - 69/udp # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b11308767849 infraserv:proxy "/usr/sbin/init" 3 minutes ago Up 3 minutes 0.0.0.0:8080->8080/tcp proxy 33054f8b7d58 infraserv:tftp "/usr/sbin/init" 35 hours ago Up 2 hours tftp 851ea861d04e infraserv:syslog "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:514->514/udp syslog dd3a657cfda2 infraserv:dhcp "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:67->67/udp dhcp 7249b9c4f11d infraserv:radius "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:1812->1812/udp radius以下のパラメータのネットワークが生成されます。
key value name infraserv_infranet subnet 172.20.0.0/24 interface docker1 tftpは
--net=host
な環境で動作しているため、docker network
は以下のような状態です。# docker network inspect infraserv_infranet [ { "Name": "infraserv_infranet", "Id": "7ed8face2e4fec3110384fa3366512f8c78db6e10be6e7271b3d92452aefd254", "Created": "2020-02-15T05:37:59.248249755-05:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.20.0.0/24", "Gateway": "172.20.0.1" } ] }, "Internal": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "7249b9c4f11de1f986892965671086d20957a6021269a5f5bc6dd85263bc0d70": { "Name": "radius", "EndpointID": "03ae6a9b9ff7817eea101955d2d6ff016982beb65c7dd6631c75c7299682c2dd", "MacAddress": "02:42:ac:14:00:04", "IPv4Address": "172.20.0.4/24", "IPv6Address": "" }, "851ea861d04edeb5f5c2498cc60f58532c87a44592db1f6c51280a8ce27940bd": { "Name": "syslog", "EndpointID": "d18e466d27def913ac74b7555acc9ef79c88c62e62085b50172636546d2e72bb", "MacAddress": "02:42:ac:14:00:03", "IPv4Address": "172.20.0.3/24", "IPv6Address": "" }, "b11308767849c7227fbde53234c1b1816859c8e871fcc98c4fcaacdf7818e89e": { "Name": "proxy", "EndpointID": "ffa6479b4f28c9c1d106970ffa43bd149461b4728b64290541643eb895a02892", "MacAddress": "02:42:ac:14:00:02", "IPv4Address": "172.20.0.2/24", "IPv6Address": "" }, "dd3a657cfda211c08b7c5c2166f10d189986e4779f1dfea227b3afe284cbafec": { "Name": "dhcp", "EndpointID": "7371f4cf652d8b1bdbf2dc1e5e8ae97013a9a70b890c2caa36c2a7cc93b165df", "MacAddress": "02:42:ac:14:00:05", "IPv4Address": "172.20.0.5/24", "IPv6Address": "" } }, "Options": { "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker1" }, "Labels": { "com.docker.compose.network": "infranet", "com.docker.compose.project": "infraserv", "com.docker.compose.version": "1.25.3" } } ]アドレスファミリ
説明を簡略するために、IPv4に絞っています。
Dockerでのパケットの流れについて
通信を追ってみる(radiusの場合)
今回は外部端末(10.254.10.105)から、Dockerホスト(10.254.10.252)あてにradiusのRequestを送付することを例にします。
自ホストに着信した後に転送されるので、注目するchainのhookは prerouting --> forward --> postrouting となります。
そのため、chainのtypeは、filterとnatだけ、に絞って説明します。ルールは
nft list ruleset
から 不要なものを除外してますが、あまり有用な情報でもないので、補足にまとめました。外部端末からのリクエスト(prerouting)
nft list ruleset
からhookがpreroutingのものを抽出すると、以下となります。table ip nat { chain PREROUTING { (1) type nat hook prerouting priority -100; policy accept; (2)-> fib daddr type local COUNTER jump DOCKER } ->(2) chain DOCKER { ↓ meta l4proto udp udp dport 514 COUNTER dnat to 172.20.0.3:514 ↓ meta l4proto udp udp dport 67 COUNTER dnat to 172.20.0.5:67 ↓ meta l4proto tcp tcp dport 8080 COUNTER dnat to 172.20.0.2:8080 (3) meta l4proto udp udp dport 1812 COUNTER dnat to 172.20.0.4:1812 } }現時点での通信は
10.254.10.105:random --> 10.254.10.252:1812
となります。
(1) preroutingをhookしてnatを行うPREROUTINGというchainが選択される
(2) DstAddrはlocalなので、DOCKERというchainに飛ぶ
addr type localは自ホスト(この場合はDockerホスト)が持つアドレスのことで、
今回ならlo:127.0.0.1
ens192:10.254.10.252
docker1:172.20.0.1
のことです。
(3) DstPortは1812なので、DstAddrを172.20.0.4:1812にDNATする
引き続きの処理がないため、policy適用 -> acceptこの時点の通信は
10.254.10.105:random --> 172.20.0.4:1812
となります。
宛先が172.20.0.4に変更されたため、 routing decision により forward の hook へ進むことになります。外部端末からのリクエスト(forward)
nft list ruleset
からhookがforwardのものを抽出すると、以下となります。table ip filter { chain FORWARD { (1) type filter hook forward priority 0; policy drop; (2)-> COUNTER jump DOCKER-USER ->(3)(4)-> COUNTER jump DOCKER-ISOLATION-STAGE-1 ->(5) oifname "docker1" ct state related,established COUNTER accept (6)-> oifname "docker1" COUNTER jump DOCKER iifname "docker1" oifname != "docker1" COUNTER accept iifname "docker1" oifname "docker1" COUNTER accept } ->(4) chain DOCKER-ISOLATION-STAGE-1 { (5)-> COUNTER return } ->(2) chain DOCKER-USER { (3)-> COUNTER return } ->(6) chain DOCKER { ↓ iifname != "docker1" oifname "docker1" meta l4proto udp ip daddr 172.20.0.3 udp dport 514 COUNTER accept ↓ iifname != "docker1" oifname "docker1" meta l4proto udp ip daddr 172.20.0.5 udp dport 67 COUNTER accept ↓ iifname != "docker1" oifname "docker1" meta l4proto tcp ip daddr 172.20.0.2 tcp dport 8080 COUNTER accept (7) iifname != "docker1" oifname "docker1" meta l4proto udp ip daddr 172.20.0.4 udp dport 1812 COUNTER accept } } table inet firewalld { chain filter_FORWARD { (8) type filter hook forward priority 10; policy accept; ↓ ct state established,related accept (9) ct status dnat accept iifname "lo" accept jump filter_FORWARD_IN_ZONES jump filter_FORWARD_OUT_ZONES ct state invalid drop reject with icmpx type admin-prohibited } chain filter_FORWARD_IN_ZONES { iifname "ens192" goto filter_FWDI_public goto filter_FWDI_public } chain filter_FORWARD_OUT_ZONES { oifname "ens192" goto filter_FWDO_public goto filter_FWDO_public } chain filter_FWDI_public { meta l4proto { icmp, ipv6-icmp } accept } chain filter_FWDO_public { jump filter_FWDO_public_allow } chain filter_FWDO_public_allow { ct state new,untracked accept } }現時点での通信は
10.254.10.105:random --> 172.20.0.4:1812
となります。
(1)forwardのhookの中で最も優先順位が高いので、filterを行うFORWARDというchainが選択される(pri:0)
(2)無条件にDOCKER-USERに飛ぶ
(3)なにもせず戻る
(4)無条件にDOCKER-ISOLATION-STAGE-1に飛ぶ
(5)なにもせず戻る
(6)出力IFはdocker1なので、DOCKERに飛ぶ
(7)入力IFはens192、出力IFはdocker1、DstAddrは172.20.0.4:1812なので、accept
regular chain のDOCKERはbase chainのFORWARDから呼び出されている。
DOCKER でacceptした時点で呼び出し元のFORWARDの評価がされ、このchainは終了する。
(8)forwardのhookの中で2番目に優先順位が高いので、filterを行うfilter_FORWARDというchainが選択される(pri:10)
(9)パケットはDNATされているので、accept
この時点の通信は最初と変わらず10.254.10.105:random --> 172.20.0.4:1812
となります。外部端末からのリクエスト(postrouting)
nft list ruleset
からhookがpostroutingのものを抽出すると、以下となります。table ip nat { chain POSTROUTING { (1) type nat hook postrouting priority 100; policy accept; ↓ oifname "docker1" fib saddr type local COUNTER masquerade ↓ oifname != "docker1" ip saddr 172.20.0.0/24 COUNTER masquerade ↓ meta l4proto udp ip saddr 172.20.0.3 ip daddr 172.20.0.3 udp dport 514 COUNTER masquerade ↓ meta l4proto udp ip saddr 172.20.0.5 ip daddr 172.20.0.5 udp dport 67 COUNTER masquerade ↓ meta l4proto tcp ip saddr 172.20.0.2 ip daddr 172.20.0.2 tcp dport 8080 COUNTER masquerade ↓ meta l4proto udp ip saddr 172.20.0.4 ip daddr 172.20.0.4 udp dport 1812 COUNTER masquerade } table ip firewalld { chain nat_POSTROUTING { (2) type nat hook postrouting priority 110; policy accept; (3)-> jump nat_POSTROUTING_ZONES } ->(3) chain nat_POSTROUTING_ZONES { ↓ oifname "ens192" goto nat_POST_public (4)-> goto nat_POST_public } ->(4) chain nat_POST_public { (5)-> jump nat_POST_public_allow } ->(5) chain nat_POST_public_allow { (6) oifname != "lo" masquerade } } }現時点での通信は
10.254.10.105:random --> 172.20.0.4:1812
となります。
(1) postroutingのhookの中で最も優先順位が高いのでnatを行うPOSTROUTINGというchainが選択される(pri:100)
引き続きの処理がないため、policy適用 -> accept
(2) postroutingのhookの中で2番目に優先順位が高いのでnatを行うnat_POSTROUTINGというchainが選択される(pri:110)
(3) 無条件にnat_POSTROUTING_ZONESに飛ぶ
(4) 無条件にnat_POST_publicに飛ぶ
(5) 無条件にnat_POST_public_allowに飛ぶ
(6) 出力IFはdocker1なので、masquerade
gotoで呼び出された先でchainが終了するため、policy適用 -> accept
regular chain のnat_POST_public_allowはregular chain のnat_POST_publicから呼び出されている。
regular chain のnat_POST_publicはregular chain のnat_POSTROUTING_ZONESからgoto命令で呼び出されている。
goto命令で呼び出されたnat_POST_publicの処理が終了した時点で、呼び出したnat_POSTROUTING_ZONESが終了し
それを呼び出したnat_POSTROUTINGも終了しpolicy accept が適用される。masqueradeの処理を受け、最終的には
172.20.0.1:random --> 172.20.0.4:1812
となります。
(docker1から送出されるため、masqueradeで処理されると、送信元アドレスがdocker1になります)radiusによる認証可否
radiusコンテナが受け取るリクエスト
172.20.0.1:random --> 172.20.0.4:1812
radiusサーバはその可否をチェックし、radiusクライアントに返答を返します。
radiusコンテナが返答するレスポンス
172.20.0.4:1812 --> 172.20.0.1:random
外部端末へのレスポンス
力尽きました。。。
nftablesでカウンタを仕掛けてみると、以下のchainを通過する際のアドレスが見えました。
1回の認証のやり取りなので、各chainで1パケットが見えていました。type filter hook prerouting : 172.20.0.4:1812 --> 172.20.0.1:random type filter hook input : 172.20.0.4:1812 --> 10.254.10.105:random type filter hook forward : 172.20.0.4:1812 --> 10.254.10.105:random type filter hook postrouting : 172.20.0.4:1812 --> 10.254.10.105:randomradiusコンテナからの返答は、
172.20.0.4:1812 --> 172.20.0.1:random
であり、
着信時は自分宛の通信に見えるから、hook:input
を通過しているのは分かります。
その後、LocalProcessを通ってforwardに行く、のでしょうか?このあたりからよくわからなくなってしまいました。。。中途半端になってしまった。。。
radiusからの応答パケットの経路がいまひとつわからない。
なぜどのchainのtype:nat
も通らないんだろう。。。
なぜhook:input
とhook:forward
を同時に通っているんだろう。。。
table bridge filter のtype:filter hook:input pri:-200
に入ってるのに
table ip filter のtype:filter hook:input pri:0
には入って行ってないんだよなぁ。
L2のブリッジとL3のIPで違う処理をしているとか?出典
https://knowledge.sakura.ad.jp/22636/
https://ja.wikipedia.org/wiki/Iptables
https://ja.wikipedia.org/wiki/Nftables
https://wiki.archlinux.jp/index.php/Nftables
https://wiki.archlinux.jp/index.php/Iptables
https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks
https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html#TRAVERSINGOFTABLES
https://wiki.archlinux.jp/index.php/Nftables
https://knowledge.sakura.ad.jp/22636/
https://www.codeflow.site/ja/article/a-deep-dive-into-iptables-and-netfilter-architecture
- 投稿日:2020-02-17T03:56:19+09:00
Docker Composeでネットワークサービス群を5分で作れるようにした(dhcp/radius/proxy/tftp/syslog)
はじめに
CentOS7で各種ネットワークサービスを基本設定したメモ(dhcp/radius/proxy/tftp/syslog)
をCentOS8で再構築しました。今回は各サービスをDockerでコンテナに閉じ込めています。自分で使う用に docker-compose を利用したところ、5分くらいで環境のリストアができるようになったので、記録に残します。
なにができるようになるのか
以下のような環境を作成できます。
docker-compose したホストの同一ポートにバインドしますので、外部端末から
ホストのアドレス:サービスのポート
にアクセスすると、各コンテナに到着します。
また、proxy,radius,dhcpは各種ログを同一ネットワーク上の syslog を待ち受けているコンテナにログを送信するようにしています。以下のコンテナが生成されます。
server app address listen proxy squid 172.20.0.2 8080/tcp syslog rsyslog 172.20.0.3 514/udp radius freeRADIUS 172.20.0.4 1812/udp dhcp ISC-Kea 172.20.0.5 67/udp tftp tftp-server - 69/udp # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b11308767849 infraserv:proxy "/usr/sbin/init" 3 minutes ago Up 3 minutes 0.0.0.0:8080->8080/tcp proxy 33054f8b7d58 infraserv:tftp "/usr/sbin/init" 35 hours ago Up 2 hours tftp 851ea861d04e infraserv:syslog "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:514->514/udp syslog dd3a657cfda2 infraserv:dhcp "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:67->67/udp dhcp 7249b9c4f11d infraserv:radius "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:1812->1812/udp radius以下のパラメータのネットワークが生成されます。
key value name infraserv_infranet subnet 172.20.0.0/24 interface docker1 tftpは
--net=host
な環境で動作しているため、docker network
は以下のような状態です。# docker network inspect infraserv_infranet [ { "Name": "infraserv_infranet", "Id": "7ed8face2e4fec3110384fa3366512f8c78db6e10be6e7271b3d92452aefd254", "Created": "2020-02-15T05:37:59.248249755-05:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.20.0.0/24", "Gateway": "172.20.0.1" } ] }, "Internal": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "7249b9c4f11de1f986892965671086d20957a6021269a5f5bc6dd85263bc0d70": { "Name": "radius", "EndpointID": "03ae6a9b9ff7817eea101955d2d6ff016982beb65c7dd6631c75c7299682c2dd", "MacAddress": "02:42:ac:14:00:04", "IPv4Address": "172.20.0.4/24", "IPv6Address": "" }, "851ea861d04edeb5f5c2498cc60f58532c87a44592db1f6c51280a8ce27940bd": { "Name": "syslog", "EndpointID": "d18e466d27def913ac74b7555acc9ef79c88c62e62085b50172636546d2e72bb", "MacAddress": "02:42:ac:14:00:03", "IPv4Address": "172.20.0.3/24", "IPv6Address": "" }, "b11308767849c7227fbde53234c1b1816859c8e871fcc98c4fcaacdf7818e89e": { "Name": "proxy", "EndpointID": "ffa6479b4f28c9c1d106970ffa43bd149461b4728b64290541643eb895a02892", "MacAddress": "02:42:ac:14:00:02", "IPv4Address": "172.20.0.2/24", "IPv6Address": "" }, "dd3a657cfda211c08b7c5c2166f10d189986e4779f1dfea227b3afe284cbafec": { "Name": "dhcp", "EndpointID": "7371f4cf652d8b1bdbf2dc1e5e8ae97013a9a70b890c2caa36c2a7cc93b165df", "MacAddress": "02:42:ac:14:00:05", "IPv4Address": "172.20.0.5/24", "IPv6Address": "" } }, "Options": { "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker1" }, "Labels": { "com.docker.compose.network": "infranet", "com.docker.compose.project": "infraserv", "com.docker.compose.version": "1.25.3" } } ]初期設定
後続の手順 で設定ファイルの修正をしない場合は、以下のパラメータで各サービスが動作します。
radius
初期状態では以下の2ユーザとenableパスワードが利用できるようになります。
ユーザ名 パスワード 備考 foo bar 通常ユーザでのログイン hoge fuga Cisco機器にログインすると自動で特権に昇格 \$enab15\$ fuga Cisco機器のenableコマンドで遷移する際のパスワード MACアドレスバイパスでは、以下のMACアドレスの場合に、ダイナミックVLAN用のアトリビュートを付与してAcceptされます。
MACアドレス VLAN文字列 112233445566 default_seg aabbccddeeff default_seg DHCP
リース情報
項目 値 リース時間 10時間 DNSサーバ 8.8.8.8 リース対象セグメント
セグメント レンジ GW 10.1.20.0/24 10.1.20.33 - 10.1.20.62 10.1.20.1 10.1.22.0/24 10.1.22.33 - 10.1.20.230 10.1.22.1 Option43によりアクセスポイントに送付するコントローラアドレス
対象 VCI文字列 コントローラアドレス Cisco Cisco AP 10.254.10.201,10.254.10.202 Aruba ArubaAP 10.254.10.206 事前準備
CentOS と Docker と Docker Compose があれば、ここの手順はスキップで 作業内容 から始めてください。
CentOS8(10分)
CentOS8は最小構成で問題ありません。
もし手元になければ、 ESXi6.7にCentOS8を最小構成で構築 を参照してください。Docker(5分)
dnf -y update dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo dnf -y --nobest install docker-ce docker-ce-cli containerd.io dnf -y update https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.10-3.2.el7.x86_64.rpm dnf -y update systemctl enable docker systemctl start dockerDocker Compose(1分)
curl -L "https://github.com/docker/compose/releases/download/1.25.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose作業内容
firewall のポリシー追加(10秒)
firewall-cmd --add-service=tftp --zone=public --permanent firewall-cmd --add-masquerade --zone=public --permanent firewall-cmd --reload各サービスのDockerコンテナをつくる(5分)
各サービスのDockerfileと設定ファイル、それらをまとめる docker-compose.yml は GitHub にあるものを使います。
git clone https://github.com/bashaway/infraservデフォルトの設定から変更する場合は、以下のエントリなどを参照してください。
設定ファイルの修正なしでもビルドには影響ありません。
ビルド後に修正しても大丈夫ですし。DHCP
DockerでKea DHCPを構築。CiscoとArubaに同時にOption43が渡せるようになった。RADIUS
DockerのFreeRADIUSでCiscoのログイン認証+MAC認証+ダイナミックVLANした(CentOS8)Proxy
DockerでproxyサーバTFTP
DockerでtftpサーバSyslog
Dockerのrsyslogでコンテナ間や他サーバから転送されるログを集約した設定ファイルの修正が終わったら、コンテナをつくります。
cd infraserv docker-compose build docker-compose up -dいらなくなったら
コンテナ削除 docker-compose stop docker-compose rm -f イメージもいらなければ docker-compose rmi -f中身の解説
docker-compose.yml
docker-compose.yml
は、以下のように構成されています。docker-compose.ymlversion: '3' services: proxy: build: ./proxy image: infraserv:proxy container_name: proxy hostname: proxy restart: always networks: infranet: ipv4_address: 172.20.0.2 ports: - 8080:8080 cap_add: - SYS_ADMIN security_opt: - seccomp:unconfined volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro environment: TZ: 'Asia/Tokyo' syslog: build: ./syslog image: infraserv:syslog container_name: syslog hostname: syslog restart: always networks: infranet: ipv4_address: 172.20.0.3 ports: - 514:514/udp cap_add: - SYS_ADMIN security_opt: - seccomp:unconfined volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro environment: TZ: 'Asia/Tokyo' radius: build: ./radius image: infraserv:radius container_name: radius hostname: radius restart: always networks: infranet: ipv4_address: 172.20.0.4 ports: - 1812:1812/udp cap_add: - SYS_ADMIN security_opt: - seccomp:unconfined volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro environment: TZ: 'Asia/Tokyo' dhcp: build: ./dhcp image: infraserv:dhcp container_name: dhcp hostname: dhcp restart: always networks: infranet: ipv4_address: 172.20.0.5 ports: - 67:67/udp cap_add: - SYS_ADMIN security_opt: - seccomp:unconfined volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro environment: TZ: 'Asia/Tokyo' tftp: build: ./tftp image: infraserv:tftp container_name: tftp hostname: tftp restart: always network_mode: host cap_add: - SYS_ADMIN security_opt: - seccomp:unconfined volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro environment: TZ: 'Asia/Tokyo' networks: infranet: driver: bridge driver_opts: com.docker.network.bridge.enable_ip_masquerade: "true" com.docker.network.bridge.host_binding_ipv4: "0.0.0.0" com.docker.network.bridge.name: "docker1" ipam: config: - subnet: 172.20.0.0/24さいごに
Dockerでコンテナにしておくと、ホスト機が汚れなくて気持ちいい
出典
- 投稿日:2020-02-17T01:54:10+09:00
Docker上でGUIのROSを一瞬でセットアップする方法
Docker上でGUIのROSを動かす
TiryohさんがGitHub上で素晴らしいリポジトリを公開していました。
Tiryoh/docker_ros-desktop-vnc(GitHub)
素晴らしさに感動してしまったので、素晴らしさを少しでも広めるために、簡単な紹介記事を書いてみます。
このリポジトリは、Docker上でGUIのROSを動かすことができます。Dockerさえ入っていればMacでもLinuxでも(多分)Windowsでも、一瞬でUbuntu+ROSの環境が手に入ります。ROSはセットアップがそれなりに大変なので、Dockerさえ入っていればコマンド一発で環境構築できるのは最高ですね。
Dockerって何?という方やインストール方法が分からない方は、以前私のブログに書いた下記記事を参照下さい。
Dockerをインストールしたら、後は以下のコマンドを実行するだけです。
$ docker run -p 6080:80 -v /dev/shm:/dev/shm tiryoh/ros-desktop-vnc:melodic初回は、イメージのダウンロードから始まるので時間かかります(2回目以降はすぐ起動します)。
Docker上でVNCが走っているので、リモートログインができます。特殊なソフトは必要なくて、好きなブラウザで以下のアドレス(自分のPCのアドレス)にアクセスするだけです。
http://127.0.0.1:6080/これで、ブラウザ上でROS環境が動きます。ヒュー!最高ですね。あとは、2つターミナル起動して、それぞれに以下のようにコマンドを打つと、おなじみのカメさんのシミュレータが動きます。
$ roscore
$ rosrun turtlesim turtlesim_node
うれしくて、Twitterで呟いたら、TiryohさんからROS2版もあるよというコメント。まさに欲しかったやつです。最高かよ!ブログ記事も楽しみです!
ありがとうございます!近々ブログに書きます……
— たいりょーくん (@Tiryoh) February 16, 2020
ROS2版もあるので、もしよければ是非!https://t.co/JlRolBxcBgROS2版のGitHubリポジトリは以下です。ROS版と同じ要領で動かせます。
- 投稿日:2020-02-17T01:54:10+09:00
Docker上でGUIのROS1/ROS2を一瞬でセットアップする方法
Docker上でGUIのROSを動かす
TiryohさんがGitHub上で素晴らしいリポジトリを公開していました。
Tiryoh/docker_ros-desktop-vnc(GitHub)
素晴らしさに感動してしまったので、素晴らしさを少しでも広めるために、簡単な紹介記事を書いてみます。
このリポジトリは、Docker上でGUIのROSを動かすことができます。Dockerさえ入っていればMacでもLinuxでも(多分)Windowsでも、一瞬でUbuntu+ROSの環境が手に入ります。ROSはセットアップがそれなりに大変なので、Dockerさえ入っていればコマンド一発で環境構築できるのは最高ですね。
Dockerって何?という方やインストール方法が分からない方は、以前私のブログに書いた下記記事を参照下さい。
Dockerをインストールしたら、後は以下のコマンドを実行するだけです。
$ docker run -p 6080:80 -v /dev/shm:/dev/shm tiryoh/ros-desktop-vnc:melodic初回は、イメージのダウンロードから始まるので時間かかります(2回目以降はすぐ起動します)。
Docker上でVNCが走っているので、リモートログインができます。特殊なソフトは必要なくて、好きなブラウザで以下のアドレス(自分のPCのアドレス)にアクセスするだけです。
http://127.0.0.1:6080/これで、ブラウザ上でROS環境が動きます。ヒュー!最高ですね。あとは、2つターミナル起動して、それぞれに以下のようにコマンドを打つと、おなじみのカメさんのシミュレータが動きます。
$ roscore
$ rosrun turtlesim turtlesim_node
うれしくて、Twitterで呟いたら、TiryohさんからROS2版もあるよというコメント。まさに欲しかったやつです。最高かよ!ブログ記事も楽しみです!
ありがとうございます!近々ブログに書きます……
— たいりょーくん (@Tiryoh) February 16, 2020
ROS2版もあるので、もしよければ是非!https://t.co/JlRolBxcBgROS2版のGitHubリポジトリは以下です。ROS版と同じ要領で動かせます。
Tiryoh/docker_ros2-desktop-vnc(GitHub)
まとめ
Docker環境のGUIにブラウザでアクセスできるの、めちゃ良いですね。この組み合わせは他にも色々応用効きそうです。