- 投稿日:2020-06-21T23:42:33+09:00
【Docker】3分でjupyterLab(python)環境を作る!
はじめに
docker-composeファイルを使ってjupyterLabの環境構築方法を記す。
python以外にもsql,R言語にも対応している。
JupyterLabとは、Jupyter(iPython notebook)をベースにしたインタラクティブな開発環境
必要なファイル、ディレクトリ
- docker-compose.yml
- jupyterLab環境に必要な設定などを記述するために使用する。
- docker runコマンドで起動することもできるが、コマンドが面倒なためこちらを使用。
- workディレクトリ
- ipynbファイルなどを保存するための使用する。
ディレクトリ構成
以下のような構成図になるようにファイル、ディレクトリを作成。
構成図. ├── docker-compose.yml ├── workdocker-compose.ymlの内容
jupyterLab環境を構築するために、docker-compose.ymlに必要な設定を記述する。
docker-compose.ymlversion: "3" services: notebook: # https://hub.docker.com/r/jupyter/datascience-notebookからimageをpullする image: jupyter/datascience-notebook # ポートの設定("ホスト:コンテナ") ports: - "8888:8888" # 環境変数の設定 environment: - JUPYTER_ENABLE_LAB=yes # ボリューム(データの永続化の場所)の設定(ホスト:コンテナ) # ホスト内のworkディレクトリとコンテナ内の/home/jovyan/workディレクトリが紐づいているイメージ volumes: - ./work:/home/jovyan/work # 最後にjupyterLabに接続するためのコマンドを実行する。 command: start-notebook.sh --NotebookApp.token=''起動方法
docker-compose.ymlを書き終えたら、以下のコマンドを実行
$ docker-compose up -d初回はimageのpullなどで時間がかかる。
コンテナが立ち上がったら、http://localhost:8888 にアクセス。
以下のような画面が立ち上がれば成功!
補足(docker runコマンドで起動したい人向け)
個人的はdocker-composeファイルを利用して起動する方法が好みだが、docker-composeファイルを作るのが面倒な方は以下のコマンドで起動することも可能。
$ docker run --rm -p 8888:8888 -e JUPYTER_ENABLE_LAB=yes -v ./work :/home/jovyan/work jupyter/datascience-notebook起動時、コンソールに以下のようなログが出てくるので、[トークン]の部分をコピ-。
Copy/paste this URL into your browser when you connect for the first time, to login with a token: http://7dae9a493ca7:8888/?token=[トークン]http://localhost:8888 にアクセス。
すると、パスワードなどを求められるので、password欄に先ほどコピーしたtokenをペースト。
すると、jupyterLabの画面となる。
- 投稿日:2020-06-21T21:00:51+09:00
OWASP ZAP2.9.0でOpenAPI定義されたAPIの脆弱性診断をする
この記事について、公式ドキュメントのZAPping the OWASP Top 10を参考にしています。このページを見てわからないことがあれば、公式ドキュメントを参照してください。
公式サイト:https://www.zaproxy.org/
ドキュメント:https://www.zaproxy.org/docs/OWASP Zed Attack Proxy (ZAP)とは
オープンソースのWebアプリケーション脆弱性診断ツールです。無料で使えて、世界で最も広く使われていると言われています。開発中に開発者が、テストとして診断する時に使えます。
なお、この記事ではOWASP ZAP2.9.0を使っています。
APIを診断する
ZAPを使って、脆弱性診断をする時に重要なことの一つに、対象のURLをもれなく抽出するということがあります。ZAPで対象URLを抽出する方法は大きく2点あります。spiderやajax spiderを使ってサイトをクロールする方法、Manual Exploreを使ってブラウザで探索する方法です。APIの場合、この2つの方法で対象を探しきることは難しいです。
そこで、ZAPでは下記2つの定義からAPIを読み込むオプションがあります。
- SOAP
- OpenAPI / Swagger
本記事では、OpenAPIで定義されたAPIを説明します。
Desktop版
OpenAPIで記述されたJSONを読み込むことで、そこに記述されたAPIをサイトツリーに取り込むことができます。
なお、Desktop版の使い方については、OWASP ZAP2.9.0で脆弱性診断をする - Getting Startedで記載しましたので参考にしてください。
add-onのインストール
「OpenAPI Support」というadd-onを追加します。
- ヘッダのアイコンをクリックして、アドオン管理ダイアログを開きます
- マーケットプレイスをクリックし、目的のアドオンを検索します
- チェックして、選択済みインストールをクリックするとインストールされます
マーケットプレイスを選択し、フィルタに「OpenAPI」と入力すると絞り込めます。チェックを入れて、選択済みをインストールされます。
OpenAPIの定義を読み込む
- Importメニューから「Import an OpenAPI definition from the local file system」を選択します
- 表示されたダイアログで、ローカルファイルを選択します
- サイトツリーにAPIが表示されます
サイトツリーに読み込まれます。Errorになった場合は、フッタメニューのアウトプットタブを見ると、エラー内容が出力されます。
読み込まれたURLに対して、スパイダー(spider)や動的スキャン(Active Scan)を実施することで診断を行うことができます。
スキャンの仕方は、OWASP ZAP2.9.0で脆弱性診断をする - Getting Startedで記載しましたので参考にしてください。Docker版
Docker版には、zap-api-scan.pyというAPIスキャンスクリプトが用意されています。これにより、コマンドラインからAPIのセキュリティスキャンを実行できます。
なお、Docker版ZAPの簡単な使い方は、Docker版OWASP ZAPを動かしてみるで記載しましたので、参考にしてください。
API Scan
API Scanは、-tオプションで指定されたAPI定義を読み込み、読み込まれたURLに対してActive Scanを実行します。API定義の形式は、-fオプションでopenapiかsoapを指定します。
docker pull owasp/zap2docker-weekly docker run -t owasp/zap2docker-weekly zap-api-scan.py -t \ https://www.example.com/openapi.json -f openapiUsage: zap-api-scan.py -t <target> -f <format> [options] -t target target API definition, currently only an OpenAPI URL, eg https://www.example.com/openapi.json -f format either openapi or soap Options: -h print this help message -c config_file config file to use to INFO, IGNORE or FAIL warnings -u config_url URL of config file to use to INFO, IGNORE or FAIL warnings -g gen_file generate default config file (all rules set to WARN) -r report_html file to write the full ZAP HTML report -w report_md file to write the full ZAP Wiki (Markdown) report -x report_xml file to write the full ZAP XML report -J report_json file to write the full ZAP JSON document -a include the alpha passive scan rules as well -d show debug messages -P specify listen port -D delay in seconds to wait for passive scanning -i default rules not in the config file to INFO -l level minimum level to show: PASS, IGNORE, INFO, WARN or FAIL, use with -s to hide example URLs -n context_file context file which will be loaded prior to scanning the target -p progress_file progress file which specifies issues that are being addressed -s short output format - dont show PASSes or example URLs -S safe mode this will skip the active scan and perform a baseline scan -T max time in minutes to wait for ZAP to start and the passive scan to run -O the hostname to override in the (remote) OpenAPI spec -z zap_options ZAP command line options e.g. -z "-config aaa=bbb -config ccc=ddd" --hook path to python file that define your custom hooks使い方は、オプションの使い方は、Baesline Scanとほとんど同じなので、Docker版OWASP ZAPを動かしてみるを参考にしてください。
ローカルファイルを指定する
ローカルからファイルを渡す場合やdockerからファイルをもらう場合、下記のように実行すると、実行したディレクトリでファイルを連携できます。
docker run -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-weekly zap-api-scan.py \ -t openapi.json -f openapiパラメータの値を指定する
スキャンする時のデフォルト値を、オプションで指定できます。OpenAPIで定義されたAPIの場合、zap_optionsで指定します。
-config formhandler.fields.field\\(0\\).fieldId=username \ -config formhandler.fields.field\\(0\\).value=test@example.com \ -config formhandler.fields.field\\(0\\).enabled=true \ -config formhandler.fields.field\\(1\\).fieldId=phone \ -config formhandler.fields.field\\(1\\).value=012345678 \ -config formhandler.fields.field\\(1\\).enabled=true上記の例だと、
username = test@example.com
phone = 012345678
というパラメータ名と値になります。実際には、こんな感じです。
docker run -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-weekly zap-api-scan.py \ -t openapi.json -f openapi \ -z "-addoninstall sqliplugin -newsession /zap/wrk/20200620_5 \ -config formhandler.fields.field\\(0\\).fieldId=email \ -config formhandler.fields.field\\(0\\).value=koujimatsuda11@gmail.com \ -config formhandler.fields.field\\(0\\).enabled=true \ -config formhandler.fields.field\\(1\\).fieldId=password \ -config formhandler.fields.field\\(1\\).value=password \ -config formhandler.fields.field\\(1\\).enabled=true"
-addoninstall sqliplugin
は、Advanced SQLInjection Scannerというアドオンを追加しています。
-newsession /zap/wrk/20200620_5
は、セッションファイルを指定しています。セッションファイルはZAPのデータファイルで、診断結果や履歴などの情報が格納され、Desktop版ZAPで開くことで見ることができます。このコマンドでは、実行したディレクトリに、20200620_5.sessionというセッションファイルができます。newsessionなので、すでにファイルがあれば、エラーになるため、自動でコマンドを実行するようにする場合は、予め作成したセッションファイルを、-sessionオプションで指定します。認証を追加する
APIには、認証を使用してAPIが保護されている場合があります。
ヘッダーを使用する場合では、別途適切な手段を使用してアプリケーションに適したトークンを取得した上で、APIスキャンではコマンドラインオプションでそれらを使うことができます。APIスキャンでは、ヘッダに認証情報をくわえるするAPIの場合、
-config replacer.full_list\\(0\\).description=auth1 \ -config replacer.full_list\\(0\\).enabled=true \ -config replacer.full_list\\(0\\).matchtype=REQ_HEADER \ -config replacer.full_list\\(0\\).matchstr=Authorization \ -config replacer.full_list\\(0\\).regex=false \ -config replacer.full_list\\(0\\).replacement=123456789 \ -config replacer.full_list\\(1\\).description=auth2 \ -config replacer.full_list\\(1\\).enabled=true \ -config replacer.full_list\\(1\\).matchtype=REQ_HEADER \ -config replacer.full_list\\(1\\).matchstr=AnotherHeader \ -config replacer.full_list\\(1\\).regex=false \ -config replacer.full_list\\(1\\).replacement=abcdefghi上記の例ですと、
Authorization: 123456789
AnotherHeader: abcdefghi
というヘッダが全てのAPIに付与されます。この機能は、Replacerというアドオンを使っております。リクエストヘッダに追加するだけではなく、置換したり削除したり、リクエストボディやレスポンスヘッダやレスポンスボディも置換することができます。例によって、ドキュメントがそんなに詳しくないので、まだ手探りですが、使えそうです。
実際には、こんな感じです。
docker run -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-weekly zap-api-scan.py \ -t openapi.json -f openapi \ -z "-addoninstall sqliplugin -newsession /zap/wrk/20200620_5 \ -config formhandler.fields.field\\(0\\).fieldId=email \ -config formhandler.fields.field\\(0\\).value=koujimatsuda11@gmail.com \ -config formhandler.fields.field\\(0\\).enabled=true \ -config formhandler.fields.field\\(1\\).fieldId=password \ -config formhandler.fields.field\\(1\\).value=password \ -config formhandler.fields.field\\(1\\).enabled=true \ -config replacer.full_list\\(0\\).description=auth1 \ -config replacer.full_list\\(0\\).enabled=true \ -config replacer.full_list\\(0\\).matchtype=REQ_HEADER \ -config replacer.full_list\\(0\\).matchstr=Authorization \ -config replacer.full_list\\(0\\).regex=false \ -config replacer.full_list\\(0\\).replacement='Bearer eyJh....Yc'"Bearer tokenを指定する場合は、半角スペースが入るのでシングルクォートで囲ってみると動きました。
結果の見方
実際にスキャンすると下記のような結果になります。
2020-06-21 11:41:38,452 Number of Imported URLs: 5 Total of 16 URLs PASS: Directory Browsing [0] (中略) PASS: Loosely Scoped Cookie [90033] WARN-NEW: A Server Error response code was returned by the server [100000] x 11 http://192.168.10.4:3000/rest/5192850544705766826 (500 Internal Server Error) http://192.168.10.4:3000/rest/user/2935822711054471034 (500 Internal Server Error) http://192.168.10.4:3000/rest (500 Internal Server Error) http://192.168.10.4:3000/rest/user (500 Internal Server Error) http://192.168.10.4:3000/rest/user/login (500 Internal Server Error) WARN-NEW: Unexpected Content-Type was returned [100001] x 19 http://192.168.10.4:3000/rest/user/login (401 Unauthorized) http://192.168.10.4:3000/644738476978233966 (200 OK) http://192.168.10.4:3000/7137581008155817315 (200 OK) http://192.168.10.4:3000/rest/5192850544705766826 (500 Internal Server Error) http://192.168.10.4:3000/rest/user/2935822711054471034 (500 Internal Server Error) WARN-NEW: Server Leaks Information via "X-Powered-By" HTTP Response Header Field(s) [10037] x 2 http://192.168.10.4:3000/rest/user/login (401 Unauthorized) http://192.168.10.4:3000/rest/user/whoami (200 OK) WARN-NEW: Content Security Policy (CSP) Header Not Set [10038] x 1 http://192.168.10.4:3000/rest/user/login (401 Unauthorized) WARN-NEW: Feature Policy Header Not Set [10063] x 1 http://192.168.10.4:3000/rest/user/login (401 Unauthorized) WARN-NEW: Cross-Domain Misconfiguration [10098] x 2 http://192.168.10.4:3000/rest/user/login (401 Unauthorized) http://192.168.10.4:3000/rest/user/whoami (200 OK) WARN-NEW: SQL Injection [40018] x 1 http://192.168.10.4:3000/rest/user/login (401 Unauthorized) WARN-NEW: ELMAH Information Leak [40028] x 1 http://192.168.10.4:3000/elmah.axd (200 OK) WARN-NEW: Trace.axd Information Leak [40029] x 1 http://192.168.10.4:3000/trace.axd (200 OK) FAIL-NEW: 0 FAIL-INPROG: 0 WARN-NEW: 9 WARN-INPROG: 0 INFO: 0 IGNORE: 0 PASS: 109パッと見、どこでどんな警告が出ているかわかりづらいです。しかも、しれっと、SQL Injection出てますし、見逃したら大変です。
Docker版OWASP ZAPを動かしてみるのconfig_fileを設定するという章でレベルの設定の変更の仕方を書きました。ただ、それよりはセッションファイルを指定しておき、そのセッションファイルをDesktop版で読み込んだ方が、見やすいと思います。アラートが出たときのリクエストの内容やレスポンスの内容も確認できますし、そのままで再リクエストもできます。うまく併用するのがいいと思います。
まとめ
OpenAPIは、超便利ですね。定義さえしっかり書いておけば、自動でコードも作成してくれますし、ZAPを使えば自動で診断環境を構築できます。Dockerであれば、Javaを追加でインストールするとか面倒な手間もいらないです。自動で診断を繰り返し行うことで、早く脆弱性に気づくことができるので、対処も早くできるようになります。ぜひ、開発段階からZAPで診断してみてください。
参考
https://www.zaproxy.org/docs/desktop/
https://www.zaproxy.org/docs/docker/
https://www.zaproxy.org/docs/docker/api-scan/
https://www.zaproxy.org/docs/desktop/addons/replacer/
- 投稿日:2020-06-21T20:44:22+09:00
dockerイメージ内にyarnをインストールする
背景
Dockerを利用して作成したRailsアプリ(v5.2.4)を本番環境にデプロイする際、アセットをプリコンパイルしようとしたところ、以下のエラーがでて実行できなかった。
$docker-compose run web bundle exec rake assets:precompile RAILS_ENV=productionStarting excite-map_db_1 ... done Yarn executable was not detected in the system. Download Yarn at https://yarnpkg.com/en/docs/instal解消方法
Dockerfileに以下を追加
RUN curl https://deb.nodesource.com/setup_12.x | bash RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list RUN apt-get update && apt-get install -y nodejs yarn postgresql-client参考
- 投稿日:2020-06-21T20:30:26+09:00
ROS melodic で ARマーカーを検出するための環境設定 ① Unbuntu 上で Docker コンテナを立ち上げるまで
はじめに
初めてROSを触る人が、DockerでROSのコンテナを立ち上げてARマーカーをUSBカメラで検出するまでの流れを記録として残します。
ROS melodicのDocekrイメージのPullから、ar-track-alvar
パッケージの動作確認までが目標です。この記事では、X serverを用いたGUI環境と、USBカメラのデバイス情報を設定して
ROS melodic
コンテナをrun するところまで紹介します。環境
環境 OS Ubuntu 18.04 LTS プロセッサ Intel Core i7-6700HQ CPU RAM 8GB GPU GeForce GTX960M ROS melodic このシリーズについて
複数回に分けて紹介します。
0. 環境設定編(Windows10にUbuntuをデュアルブートして、Dockerをセットアップする)
1. ROSのコンテナを作成する この記事です
2. AR検出用のパッケージをセットアップするdocker imageのインストール
ROS1の中では melodicが最新なのでイメージをインストールします
ターミナルで以下を実行してください。イメージのダウンロード$ docker pull {image-name:tag-name} 例 $ docker pull orsf/ros:melodic-desktop-full-bionicタグの中身の違いは現状わかっていません。
例えば、stretchとか検索するとraspbianというワードが出るから、リソース小さいマシン用なのかな?ちなみにpull済のイメージ一覧は次のコマンドで知ることができます。
pull済のイメージの確認$ docker image lscontainer の起動
イメージからコンテナを作成します。
このときに外部接続の設定と、USB deviceの設定をしないとROSコンテナ内でGUI画面が出てきません。(エラーメッセージ
cannot connect X server
とか、カメラ画像が出てこない事象に悩みます。)docker tutorialのスクリプトを参考にrun スクリプトで設定を
行いました。コンテナのrun$ docker run -it \ --env="DISPLAY" \ --env="QT_X11_NO_MITSHM=1" \ --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \ --device="/dev/video2:/dev/video2" \ --name="AR_Env" \ osrf/ros:melodic-desktop-full-bionic \ rqt export containerId=$(docker ps -l -q)
device
やname
, 使うイメージは適宜読み替えてください。
次の項で、デバイス情報取得で調べ方を記述します。usbカメラデバイス
device
の情報取得Ubuntu側でUSBデバイスの確認$ lsusb
コマンドがないときは、
$ apt-get install lsusbでインストールできます
これだとPCのビルトインcamの情報が出ました$ v4l2-ctl -d /dev/video0 --all私の環境の場合、
/dev/video2
がusbcamだったのでこちらの情報を使っています。X severの準備
noVNCとか使いたかったのですが、いまのところ難しかったのでdocker tutorialより
シンプルだけど、安全でない 方法でとりあえず動かします。runのスクリプトを実行する前に、Ubuntu側のX server設定を変更しておきます。
$ xhost +local:root
Ubuntuを立ち上げる都度設定してあげないと、作ったコンテナがstart しないという事態を経験します。
そうゆうときはconteinorのlogを確認$ docker logs {container name}で何が起こっているか見ることができます。(Xseverに繋がらないからstartできない、とか)
コンテナのrunスクリプトを実行すると起動します。
device
で設定したUSBカメラを接続していないとコンテナがstartしないのでご注意ください。おわりに
USBカメラを接続した状態でROSのコンテナが起動でき、撮影した画像をGUIで表示する準備ができました。
- 投稿日:2020-06-21T18:35:20+09:00
Ubuntu 20.04 command-not-foundとの格闘
command-not-foundが使えない!!
インストールしてないコマンドを叩いた際に、どのパッケージをインストールすればいいかを表示してくれるcommand-not-found。
大変重宝していたのだけれど、ubuntu20.04にしてからちゃんと動かないのでどうしたものかな、、と放置していた。
流石に放置し続けもどうかなということで、原因と対策を調べてみた。環境
docker ubuntu:20.04(latest, 2020.6時点)。
ちなみに後述するが、dockerのubuntu:18.04及びminimumインストールしたubuntu 20.04(server)では本事象は発生しない。事象
これまで通りインストールしてないコマンドをコンソールで叩いてみると、、
Could not find command-not-found database. Run 'sudo apt update' to populate it.
てな具合に、command-not-foundをつかいたいなら、まずupdateせよと。
で、アップデートしてみると、、# apt-get update Get:1 http://security.ubuntu.com/ubuntu focal-security InRelease [107 kB] Hit:2 http://archive.ubuntu.com/ubuntu focal InRelease Get:3 http://archive.ubuntu.com/ubuntu focal-updates InRelease [107 kB] Get:4 http://archive.ubuntu.com/ubuntu focal-backports InRelease [98.3 kB] Fetched 312 kB in 2s (168 kB/s) Traceback (most recent call last): File "/usr/lib/cnf-update-db", line 26, in <module> col.create(db) File "/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py", line 99, in create self._fill_commands(con) File "/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py", line 133, in _fill_commands self._parse_single_commands_file(con, fp) File "/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py", line 177, in _parse_single_commands_file suite=tagf.section["suite"] KeyError: 'suite' Reading package lists... Done E: Problem executing scripts APT::Update::Post-Invoke-Success 'if /usr/bin/test -w /var/lib/command-not-found/ -a -e /usr/lib/cnf-update-db; then /usr/lib/cnf-update-db > /dev/null; fi' E: Sub-process returned an error code(creator.pyは、内部の動作確認のために少し書き換えてるので、エラー行は本来とずれてます)
そもそもアップデートができない。。。
これはcommand-not-foundに限らずアップデート全般ができなくなるので、かなり由々しき問題なわけです。なぜこうなった?
エラーを起こしている箇所は、エラーログのとおり、/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py。
これはcommand-not-foundが、どのコマンドにはどのpkgが必要という情報を管理するDBを作成する際の処理で、apt-get update時に/usr/lib/cnf-updatedb経由で呼び出される。
内部をみていくと、apt_pkgというライブラリで/var/lib/apt/listsにある、apt情報を読み込んで、sqliteのDBを作ろうとしています。
この際、/var/lib/apt/lists配下のファイルはlz4で圧縮されてるのですけれど、これを解凍せずに読み込んでいるのでapt_pkgがデータを解釈できなくなってるのが原因、、、と思われる。docker 18.04ではなぜ動く?
18.04も、creator.pyの処理や、lists配下のlz4圧縮といった条件は一緒っぽい。
ただし、command-not-foundのpkgを導入する際、合わせてcommand-not-foundの対応表のDB(/usr/share/command-not-found/commands.db)を配置してくれる。
これで、command-not-foundがちゃんと動くようである。一方、creator.py(というか、それを呼び出している/usr/lib/cnf-update-db)を実行してみると、、
正常終了する、、、けど、実は何も仕事してない。
これは、内部の処理をよくよく見ると、/var/lib/apt/lists配下の全ファイルではなくCommandが名前にファイルだけを読み込むようにしているのだけど、apt-get時にCommandをダウンロードしてこないため、そもそも何も処理をしないから、ということっぽい。仮想マシンにきちんとインストールした20.04では、、
ちゃんと動作する。
command.dbの場所が/var/lib/connamd-not-foundで少々ずれているが、まぁそれはいいとして。
また、/usr/lib/cnf-update-dbもちゃんと動く。
違いはというと、、、/var/lib/apt/lists配下のファイルがすべて生データで、lz4圧縮されてない!!そもそも/var/lib/apt/listsて?
docker関連で調べてみたところ、コンテナ化の際ここは重いからまるごと削除してしまうものらしい。
ってことは、、、
あった。。。
dockerの場合、/etc/apt/apt.conf.d/docker-gzip-indexesAcquire::GzipIndexes "false"; Acquire::CompressionTypes::Order:: "gz";apt-get updateするなら持ってきてもいいけど、圧縮はするからね!という設定ですね。。
これを削除して、apt-get updateすると、無事lz4圧縮しないファイルが取得できました。
そしてcommand.dbも無事生成完了。まとめ
command-not-foundを使うには、/var/lib/apt/lists配下の情報を圧縮せずに持ってこないといけない。
dockerはディスク膨張を嫌ってこのファイルは基本削除/持ってきても圧縮保存、としているので、その基本設定と干渉しちゃったのが問題っぽい。
ターミナル用途でdocker使うなよ、、、てことなんでしょうけれど、ターミナル用とで使いたい私からすると致し方なし。
まぁ、勉強にはなりました。apt-fileでも良かったんですけど、そっちも同じような問題にぶつかったのかなぁ。。
気が向いたらまた調べて見るくらいで。
- 投稿日:2020-06-21T18:27:15+09:00
dockerfileでパスワードを求めないsudoer作り(Alpine、Debian、Ubuntu、Centos)
紹介する内容
- Alpine、Debian、Ubuntu、Centosの例です
- uidとデフォルトshell設定を含みます
結論
- Alpine linux他はsudoerの作り方が似てます
- dockerのvolumeでpermission denied問題解決や、作りたいときに使えます
紹介始めます
ディレクトリ構成
全体ソースコードは https://github.com/cheekykorkind/qiita-example/tree/master/dockerfiles/no-password-sudoer で確認できます
- 全体図 Dockerfileの名はどのLinuxかをわかりやすく表現しました。
AlpineDockerfileはAlpine 3.11
、
CentosDockerfileはCentos 7
、
DebianDockerfileはDebian buster
、
UbuntuDockerfileはubuntu 18.04
。Dockerfileの中身
- AlpineDockerfile
- Alpine linuxだけがsudoerの作り方が違う気がします
FROM alpine:3.11 RUN apk add sudo RUN adduser -D -u 1001 -s /bin/sh -G wheel alpine-sudoer RUN echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
- CentosDockerfile
FROM centos:7 RUN yum -y install sudo RUN useradd --uid 1001 --create-home --shell /bin/bash -G wheel,root centos-sudoer RUN echo '%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
- DebianDockerfile
FROM debian:buster-slim RUN apt update && apt install -y sudo RUN useradd --uid 1001 --create-home --shell /bin/sh -G sudo,root debian-sudoer RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
- UbuntuDockerfile
FROM ubuntu:18.04 RUN apt update && apt install -y sudo RUN useradd --uid 1001 --create-home --shell /bin/bash -G sudo,root ubuntu-sudoer RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers試し順番です
デレクトリー移動
cd qitta-example/dockerfiles/no-password-sudoer
dockerコンテナをバックグラウンドで起動
docker-compose up -d
各々のdockerコンテナにsudoerが作られたか確認します
docker exec -it alpine-sudoer /bin/sh -e -c "cat /etc/passwd | grep alpine-sudoer"
docker exec -it debian-sudoer /bin/sh -e -c "cat /etc/passwd | grep debian-sudoer"
docker exec -it ubuntu-sudoer /bin/bash -e -c "cat /etc/passwd | grep ubuntu-sudoer"
docker exec -it centos-sudoer /bin/bash -e -c "cat /etc/passwd | grep centos-sudoer"
(選択)自由に確認したいなら、入りたいdockerコンテナに入ります
docker exec -it alpine-sudoer /bin/sh
docker exec -it debian-sudoer /bin/sh
docker exec -it ubuntu-sudoer /bin/bash
docker exec -it centos-sudoer /bin/bash
- 投稿日:2020-06-21T17:06:59+09:00
環境を汚さず(選ばず)Nuxtプロジェクトを作成しGitHub Pagesで公開するまでの一部始終
事前準備
docker がインストールされていることが前提です。
docker が入ってさえいれば Windows, Mac, Linux いずれでも同じように操作できるはずです。WindowsにDockerを導入する方法は以下にまとめています。
また、プログラムの編集にはVisualStudioCodeを使いますのでインストールしておいてください。
GitHubからクローンしたりプッシュしたりするのでGitHubのアカウントを用意し git もインストールしておいてください。
プロジェクト作成
プロジェクトを作る親フォルダに移動
(Windows の場合は例えば C:\dev を作ってコマンドプロンプトでcd \dev
で親フォルダとする dev に移動します。)
node.jsが入ったLinuxを起動するため以下のコマンドを実行します。
windowsdocker run --rm -itv %cd%:/app node:alpine shmac,linuxdocker run --rm -itv $PWD:/app node:alpine shdocker run は指定したイメージ(node:alpnine)からコンテナを作り、指定したコマンド(sh)を実行します。
--rm オプションは実行後にコンテナを削除します。これをつけないと docker run するごとにコンテナが増えていきディスクを圧迫します。
今回は作成したファイルはローカルに同期して残りますので、作業時以外コンテナは不要です。
-it は起動したコンテナに対して入力できるようにするためのオプションです。指定しないとコマンドが即終了してしまいます。
-v でローカルの$PWD or %cd%(カレントディレクトリ)とコンテナ内の /app を同期(ファイルやフォルダの内容がおなじになる)します。
コマンドが実行されると、Dockerコンテナ内のシェルに切り替わります。
Dockerコンテナ内/ #
/ は現在ルートディレクトリにいるということ、
# はルートユーザを表しています。
node:alphine イメージを使っているのでnode環境は既にあります。
以下のコマンドで同期している /app フォルダに移動して first_nuxt という名前のプロジェクトを作成します。Nuxtプロジェクト作成/ # cd /app && yarn create nuxt-app first_nuxt
yarn create next-app としてしまうとReactベースの Next.js のプロジェクトになってしまいますので間違わないように注意しましょう。
実行すると以下のように表示されます。
プロジェクト名入力yarn create v1.22.4 [1/4] Resolving packages... warning create-nuxt-app > sao > micromatch > snapdragon > source-map-resolve > resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated warning create-nuxt-app > sao > micromatch > snapdragon > source-map-resolve > urix@0.1.0: Please see https://github.com/lydell/urix#deprecated [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh packages... success Installed "create-nuxt-app@3.0.0" with binaries: - create-nuxt-app create-nuxt-app v3.0.0 ✨ Generating Nuxt.js project in first_nuxt ? Project name (first_nuxt)プロジェクト名を聞かれていますが、コマンド実行時に指定している first_nuxt でいいので、そのまま Enter を押します。
言語選択? Choose programming language (Use arrow keys) ❯ JavaScript TypeScript使うプログラミング言語を聞かれています。今回は JavaScript にしますのでそのまま Enter を押します。
パッケージ管理選択? Choose the package manager (Use arrow keys) ❯ Yarn Npm使うパッケージ管理を聞かれています。今回は最初に Yarn を使っていますので、そのまま Enter を押します。
UIフレームワーク選択? Choose UI framework (Use arrow keys) ❯ None Ant Design Vue Bootstrap Vue Buefy Bulma Element Framevuerk iView Tachyons Tailwind CSS Vuesax Vuetify.js使う UIフレームワークを聞かれています。今回は自分でUIを作るので None(なし)にします。そのまま Enter を押します。
この辺りからはプロジェクト作成後に追加することもできますので、よくわからなければ None で大丈夫です。
モジュール選択? Choose Nuxt.js modules (Press <space> to select, <a> to toggle all, <i> to invert selection) ❯◯ Axios ◯ Progressive Web App (PWA) Support ◯ Content使うモジュールを聞かれています。
Axios はWebAPIを呼ぶときに使うものです。
PWA Support は Webサービスをスマートフォンのアプリのように使うようにするためのしくみです。
Content はブログ作成のためのモジュールです。
上下矢印キーで選択し、スペースキーを押すと選択/未選択を切り替えられます。
必要なら後から追加できるので、今回はそのまま Enter を押します。
チェックツール選択? Choose linting tools (Press <space> to select, <a> to toggle all, <i> to invert selection) ❯◯ ESLint ◯ Prettier ◯ Lint staged files ◯ StyleLint使うチェックツールを聞かれています。
今回はVSCodeの拡張機能でチェック等を行うので、そのまま Enter を押します。
テストツール選択? Choose test framework (Use arrow keys) ❯ None Jest AVA WebdriverIO使うテストフレームワークを聞かれています。
後から使いできるのでそのまま、Enter を押します。
レンダリング方式選択❯ Universal (SSR / Static) Single Page App使うレンダリング方式を聞かれています。
SSR(Server Side Rendering)というのはサーバサーイドでHTMLを組み立ててブラウザに返す方式です。
Single Page App(SPA)はブラウザ側でページを組み立てる方式です。
今回は静的ファイルを生成して GitHub Pages に置くのでどちらでもいけますが、そのまま Enter を押します。
開発ツール選択? Choose development tools (Press <space> to select, <a> to toggle all, <i> to invert selection) ❯◯ jsconfig.json (Recommended for VS Code) ◯ Semantic Pull Requests使う開発ツールを聞かれています。
今回はVSCodeを使うので、 jsconfig.json をスペースで選択して Enter を押します。
質問はこれで終わりです。しばらく待っていれば以下のような完了表示が出ます。
Nuxtプロジェクト作成完了? Choose development tools jsconfig.json (Recommended for VS Code) ? Successfully created project first_nuxt To get started: cd first_nuxt yarn dev To build & start for production: cd first_nuxt yarn build yarn start Done in 2842.73s.ls で生成されたフォルダ、ファイルを確認してみましょう。
生成されたファイル確認/app # ls first_nuxt
ローカルの first_nuxt フォルダにコンテナの first_nuxt 内と同様下記のファイルが作成されていることが確認できます。
生成されたファイル一覧README.md components layouts node_modules package.json plugins store assets jsconfig.json middleware nuxt.config.js pages static yarn.lockこれでプロジェクト作成は完了です。
開発モードで起動してみましょう。
まず、プロジェクトフォルダに移動します。
プロジェクトフォルダへ移動/app # cd first_nuxt
yarn dev コマンドを実行します。
開発サーバ起動/app/first_nuxt # yarn dev yarn run v1.22.4 $ nuxt ℹ NuxtJS collects completely anonymous data about usage. 12:06:56 This will help us improving Nuxt developer experience over the time. Read more on https://git.io/nuxt-telemetry ? Are you interested in participation? (Y/n)使用状況の匿名データ収集をしてもいいか聞かれますので、OKならY、NGならnを入力し、Enterを押します。
╭───────────────────────────────────────╮ │ │ │ Nuxt.js @ v2.13.0 │ │ │ │ ▸ Environment: development │ │ ▸ Rendering: server-side │ │ ▸ Target: server │ │ │ │ Listening: http://localhost:3000/ │ │ │ ╰───────────────────────────────────────╯ ℹ Preparing project for development 12:11:17 ℹ Initial build may take a while 12:11:17 ✔ Builder initialized 12:11:17 ✔ Nuxt files generated 12:11:17 ✔ Client Compiled successfully in 10.22s ✔ Server Compiled successfully in 10.14s ℹ Waiting for file changes 12:11:33 ℹ Memory usage: 125 MB (RSS: 211 MB) 12:11:33 ℹ Listening on: http://localhost:3000/ 12:11:33Listening on の行が表示されれば起動完了です。
コンテナ内の3000番ポートで動作しています。
ブラウザでの動作確認
起動した画面をブラウザで確認したいですよね。
でも今の状態だと、ブラウザで http://localhost:3000 にアクセスしても何も表示されません。
なぜかというと、コンテナ内の 3000 ポートは何も設定しないとローカル(PC)からアクセスできないようになっているからです。
ですので、いったんコンテナを終了して、設定を追加してもう一度コンテナを起動します。
Ctrl+Cを押して開発サーバを終了させて、 exit コマンドでコンテナから抜けます。/app/first_nuxt # exit
まず、作成したプロジェクトフォルダに移動します。
共通cd first_nuxt
以下のコマンドで開発サーバを起動します。
windowsdocker run --rm -itv %cd%:/app -p 80:3000 -e "HOST=0.0.0.0" -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn devmax,linuxdocker run --rm -itv $PWD:/app -p 80:3000 -e "HOST=0.0.0.0" -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn devいくつかオプションが増えていますが、意味は次の通りです。
-v %cd%:/app は先程と同じ記述ですが、first_nuxtがカレントフォルダなので、first_nuxt とコンテナ内の /app が同期するようなります。
-p 80:3000 とするとコンテナの3000番ポートがローカルの80番ポートにつながります。
-e "HOST=0.0.0.0" でコンテナの環境変数 HOST に 0.0.0.0 が設定され開発サーバがコンテナ以外のホスト(今回はローカル)からつながるようになります。
-e "NUXT_TELEMETRY_DISABLED=1" で使用状況の匿名データ収集について聞いてこなくなります。
-w でコンテナのカレントディレクトリをプロジェクトのディレクトリに設定しています。
sh を yarn dev に変えていきなり開発サーバを起動するようにします。これで、ブラウザを開いて http://localhost と入れればコンテナ内に起動したページを見ることができます。
ソース編集と自動更新の設定
これで開発できる状態になりました。
さっそく、表示されたトップページを変更してみます。first_nuxt フォルダを VisualStudioCode で開きます。
Windowsならフォルダ右クリックで Code で開くを選択します。
(VisualStudioCodeを起動してからフォルダを開くでもOKです)
トップページの編集
pages フォルダ内に index.vue というファイルがあります。
これがトップページの内容になります。<template> タグ内が表示内容を構成するHTMLです。(通常のHTMLだけではなくVueの記法が使えるようになっています)
<h1>タグ内にタイトルの文字 first_nuxt があるので、
「はじめてのNuxt」に変えてみましょう。
(ファイルを編集するとファイル名タブに●がつきます。保存すると消えます。)
変更の反映
WindowsならCtrl+S、MacならCommand+Sでファイルが保存できます。
保存すると、おそらくMacやLinux環境ならすぐにブラウザの内容が自動更新され文字が変わります。
Windows環境やうまく自動更新されない場合は、次の設定をしてみてください。
(Windowsで)自動更新が効かない場合の設定
nuxt.config.js ファイルを開き、末尾に以下の記述を追加して保存します。
変更前build: { } }変更後build: { }, watchers: { webpack: { poll: true } } }そしていったん docker コンテナから抜けて(CTRL+C)以下のコマンドで再度開発環境を起動します。
windowsdocker run --rm -itv %cd%:/app -p 80:3000 -e "HOST=0.0.0.0" -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn devmax,linuxdocker run --rm -itv $PWD:/app -p 80:3000 -e "HOST=0.0.0.0" -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn devこれでソースを変更して保存するとすぐにブラウザの表示内容が切り替わるようになります。
試しに、タイトルを「Nuxtはじめました」に変えてみましょう。
拡張機能を入れる
vueファイルを見やすくしたり、ミスを教えてくれたりする拡張機能を入れておきます。
検索欄に vetur と入れて Vetur という拡張機能を探します。
見つけたら install ボタンを押しまてインストールします。インストールできると以下のようにに内容が色分けして表示されます(シンタックスハイライトといいます)
余分なポートの通信を止める
ブラウザでF12を押し開発者ツールを出します。
そうすると、以下のようにエラーが出ているのが確認できると思います。
エラーを見ると localhost の 40791 ポートにアクセスしようとしてエラーになっています。
(このポート番号はプロジェクトごとにランダムで変わります。)
このポートも -p 80:3000 としたように Docker 内のポートにつなげないと通信できません。これは、Nuxtの自動ロード時に進捗率を表示するために使われているようです。
https://ja.nuxtjs.org/api/configuration-build/#indicator
エラーは出てほしくないのでこの設定をOFFにします。nuxt.config.js ファイルを開き、以下のように変更して保存します。
変更前build: { },変更後build: { indicator: false },もしくは、ONのままにしたい場合は、docker run 実行時に -p 40791:40791 のようにポートの通信を通すようにします。
github pages に公開する
まだトップページしかありませんが、動作はするので、これを Github pages にデプロイしてみましょう。
静的ファイルの生成
docker コンテナを一度終了して、以下のコマンドを実行します。
windowsdocker run --rm -itv %cd%:/app -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn generatemax,linuxdocker run --rm -itv $PWD:/app -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn generate実行結果yarn run v1.22.4 $ nuxt generate ℹ NuxtJS collects completely anonymous data about usage. 07:35:21 This will help us improving Nuxt developer experience over the time. Read more on https://git.io/nuxt-telemetry ? Are you interested in participation? No ℹ Production build 07:35:42 ℹ Bundling for server and client side 07:35:42 ℹ Target: static 07:35:42 ✔ Builder initialized 07:35:42 ✔ Nuxt files generated 07:35:42 ✔ Client Compiled successfully in 20.32s ✔ Server Compiled successfully in 601.69ms Hash: f6c77d51cae28b7be227 Version: webpack 4.43.0 Time: 20320ms Built at: 06/20/2020 7:36:19 AM Asset Size Chunks Chunk Names ../server/client.manifest.json 6.68 KiB [emitted] LICENSES 389 bytes [emitted] app.656ba39.js 51.3 KiB 0 [emitted] [immutable] app commons.app.4dd2efa.js 154 KiB 1 [emitted] [immutable] commons.app pages/index.573dd1d.js 2.85 KiB 2 [emitted] [immutable] pages/index runtime.b17d028.js 2.32 KiB 3 [emitted] [immutable] runtime + 2 hidden assets Entrypoint app = runtime.b17d028.js commons.app.4dd2efa.js app.656ba39.js Hash: 28f709d14cc9b922eefa Version: webpack 4.43.0 Time: 603ms Built at: 06/20/2020 7:36:19 AM Asset Size Chunks Chunk Names pages/index.js 11.9 KiB 1 [emitted] pages/index server.js 80.5 KiB 0 [emitted] app server.manifest.json 207 bytes [emitted] + 2 hidden assets Entrypoint app = server.js server.js.map ℹ Generating output directory: dist/ 07:36:19 ℹ Generating pages 07:36:19 ✔ Generated route "/" 07:36:19 ✔ Client-side fallback created: 200.html 07:36:20 Done in 72.08s.これらのファイルをレンタルサーバ等に置けばインターネット上に公開できます。
今回はこのファイルを GitHub Pages で公開します。
GitHub には GitHub Actions というコマンド実行機能がありますので、それを使って、push 時今の生成操作を自動実行して公開できるように設定していきます。
GitHub Actions 用ファイルの作成
FIRST_NUXT フォルダ直下に .github/workflows フォルダを作成します。
具体的には、nuxt.config.jsなど直下のファイルを選択した状態で
フォルダ作成ボタンを押します。出てきたフォルダ名入力欄に .github/workflows を入力します。(先頭のピリオドを忘れないでください)
作成したworkflowフォルダを選択した状態で、ファイル作成ボタンを押して、gh-pages.yml ファイルを作成します。
.github/workflows/gh-pages.ymlname: github pages on: push: branches: - master jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 - run: yarn generate - uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dist
GitHubリポジトリの作成
下記の記事にGitHubのアカウント作成からプッシュするまでをまとめていますので参考にして、
リポジトリ作成まで(「ローカルにクローンする」の手前まで)進めてください。
ローカルのGit管理開始
ローカルで Git の初期化を行います。
first_nuxt フォルダ上で git init コマンドを実行します。
git初期化git init初期化したあと、VisualStudioCodeのソース管理を見ると、
gitでまだコミットされていないファイルが列挙されてきます。
GitHubリポジトリをリモートリポジトリとしてセット
ローカルのgitリポジトリとGitHubのリポジトリを関連付けます。
リモートリポジトリ設定git remote add origin https://github.com/GitHubアカウント名/リポジトリ名.git※GitHubアカウント名、リポジトリ名はご自身で作成したものを指定します。
登録されたかどうかは
git remote -v
で確認できます。
コミットする
VisualStudioCodeでソース管理の上部分にコミットコメントを入力します。
今回は「初コミット」としています。
ステージされていないファイルをコミットするかの確認が出ます。全ファイルコミットするので Yes を押します。
以下の画面が出る場合はCancelボタンを押して、git config コマンドで名前とメールアドレスを設定してから再度コミットしてください。
名前、メールアドレス設定git config user.name あなたの名前 git config user.email GitHubに登録したメールアドレス
GitHub に push
2回目以降はPush先が記録されるので Push to ではなく Push で実行可能です。
GitHubにログインしていない場合は以下の画面が出ます。ログインします。
上向きの矢印が出ない状態になっていればPushされています。
動作確認
Pushすると GitHub Actions が実行され GitHub Pages にページが公開されているはずです。
公開先URLは以下の通りです。
https://GitHubのユーザ名.github.io/プロジェクト名(今回はfirst_nuxt)/例えば私が作ったURLは
https://github-japanese-user.github.io/first_nuxt/
になります。
もし、404エラーが表示される場合は正しくHTMLが登録されている確認します。
GitHub Pages に公開されているかを確認する
GitHubのリポジトリページに行き、Branchボタンを押して、gh-pages を選択します。
gh-pages というのが生成されたHTMLが格納されているブランチになります。gh-pages のファイル内に index.html があれば生成は成功しています。
次に、設定を確認します。
設定画面の下を見ていくと、GitHub Pages の設定部分があります。
ここの Source が gh-pages branch になっているか確認します。
また、緑で Your site・・・と表示されていればリンクをクリックすればサイトが表示されます。
もし、設定もあっていて、index.html も生成されているのに、リンクが表示されていない場合は、
一旦、Sourceの部分を master に切り替えて、https://GitHubのユーザ名.github.io/プロジェクト名(今回はfirst_nuxt)/README.md
がブラウザで表示できることを確認してから、
再度、Sourceの部分を gh-pages に切り替えるとうまくいくようです。
URLの調整
これで、完成のように見えますが、トップページの裏でエラーが発生しています。
F12で開発者ツールを出し、Networkタブを開くと、404エラーになっているファイルが見つかります。
これは、通常Nuxtで作ったプロジェクトはルートで動作する設定になっているためです。
https://GitHubのユーザ名.github.io/
が基準となっており、実際のルートとなる
https://GitHubのユーザ名.github.io/プロジェクト名(今回はfirst_nuxt)/
とズレがあるため、相対パスがおかしくなるのが原因です。最後にこれを解決する設定を行います。
VisualStudioCode で nuxt.config.js を開き、以下の通り変更します。
nuxt.config.js変更前link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } ] }, /* ** Global CSS */nuxt.config.js変更後link: [ { rel: 'icon', type: 'image/x-icon', href: '/first_nuxt/favicon.ico' } ] }, router: { base: '/first_nuxt/' } /* ** Global CSS */linkのhrefの修正と、router: の追加です。
これで、相対パスのルートの設定が / から /first_nuxt/ に変更されます。
最終確認
変更したソースをコミットして、プッシュします。
変更内容はソース管理の nuxt.config.js を選択すると確認できます。
変更前と後の内容が左右に並び、変更した行がマークされています。
これをみて間違いがないかを確認できたら、コミットコメント
を入力して、コミットボタンを押します。
Push すると GitHub Action が動作しますので、GitHubのリポジトリページから Actions タブを開いて
動作が完了しているか確認してみましょう。
ブラウザでトップページをリロードして404エラーが消えていることを確認します。
長くなりましたが、以上ですべての作業が完了しました!
- 投稿日:2020-06-21T16:38:29+09:00
よく使うDockerコマンドまとめ
この記事について
この記事は、
- 開発時に私個人がよく使うdockerコマンド
- 開発時に気になったdockerコマンドの細かい挙動
- コンテナを支えるネットワーク・ボリュームといった裏の仕組み
だけに絞って書き残したものです。
「よく使うコマンドだけ手っ取り早く知りたい」「コンテナという概念は知っている状態から、もっとdockerシステムについての理解を深めたい」という人には役立つかもしれません。注:「コンテナについての一からの解説が欲しい」「dockerコマンドにはどういう機能があるのかを網羅的に知りたい」という方のニーズは満たせていません。
使用する環境・バージョン
- Mac OS Mojave 10.14.5
- Docker version 19.03.8
Containers
コンテナの新規作成・起動
docker run
は指定したイメージから新しくコンテナを作成・起動するコマンドです。ただし、コンテナの元になるイメージ(
Dockerfile
のFROM
命令で指定されたもの)がローカルにまだインストールされていない場合、DockerデーモンがそのコンテナイメージをDocker Hub(Docker社が運営するPaaS型のDocker Registry)から自動でダウンロードし、イメージからコンテナを起動します。
この挙動から、docker run
は「docker pull
→docker create
→docker start
」と同じ動作であると言えます。
参考:さわって理解するDocker入門 第1回 Dockerのイメージ・コンテナ管理の仕組みコマンドオプションについては以下の通りです。
-p XXXX:YYYY
: localhost:XXXXをコンテナポートYYYYにリダイレクト-d
: デタッチモード(コンテナ内に入らずに、バックグラウンドで作動させる)での起動$ docker run -p 80:3000 -d <起動したいイメージ名>ここで注意したいのは、
docker run
コマンドは「イメージからの新規作成」であるという点です。
そのため、docker run ImageA
というコマンドを二回叩くと、 ImageAを使用したコンテナが2つできることになります。# 1回目のdocker run $ docker run -p 80:8080 -d ImageA $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dd1e156a0d6a ImageA "go run main.go" 39 seconds ago Up 38 seconds 0.0.0.0:80->8080/tcp cool_buck $ docker stop dd1e156a0d6a # 2回目のdocker run $ docker run -p 80:8080 -d ImageA $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS 55f3cccb4b33 ImageA "go run main.go" 3 seconds ago Up 2 seconds 0.0.0.0:80->8080/tcp jolly_pasteur # さっきと違うコンテナIDのものが立ち上がってることが確認できる $ docker stop 55f3cccb4b33 # 存在するコンテナ一覧の確認 $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 55f3cccb4b33 ImageA "go run main.go" 3 seconds ago Exited (2) 4 minutes ago jolly_pasteur dd1e156a0d6a ImageA "go run main.go" 7 minutes ago Exited (2) 6 minutes ago cool_buck # ImageAを元にしたコンテナが2つ立ち上がってることが確認できるそのため、「既に存在するコンテナを起動させる」という場合は、次の
docker start
コマンドを使用する必要があります。指定コンテナの起動
既に存在する停止中コンテナを起動したい場合は、
docker start
を使います。
コンテナの指定は、コンテナIDかコンテナ名を使います。$ docker start <container ID> # または $ docker start <container Name>備考: コンテナIDやコンテナ名を知りたい場合は、後述する
docker ps
コマンドを使います。コンテナの停止
ある特定のdockerコンテナを停止させるには、
docker stop
を使います。$ docker stop <container ID> # または $ docker stop <container Name>備考: コンテナIDやコンテナ名を知りたい場合は、後述する
docker ps
コマンドを使います。コンテナ一覧の確認
docker ps
コマンドで、現在稼働中のコンテナ一覧が確認できます。CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 55f3cccb4b33 ImageA "go run main.go" 3 seconds ago Up 2 seconds 0.0.0.0:80->8080/tcp jolly_pasteur
停止中のコンテナまで含めた全てのコンテナを確認したい場合は、オプション
-a
をつけます。$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 55f3cccb4b33 ImageA "go run main.go" 3 seconds ago Up 2 seconds 0.0.0.0:80->8080/tcp jolly_pasteur dd1e156a0d6a ImageA "go run main.go" 7 minutes ago Exited (2) 6 minutes ago cool_buckこれら2つのコマンドで、以下のことが確認できる。
- CONTAINER ID : コンテナID
- IMAGE : そのコンテナの元となったイメージ
- COMMAND : コンテナ起動時にコンテナ中で実行されたコマンド(
Dockerfile
のCMD
命令にあたる)- CREATED : 作成日時
- STATUS : 起動中か、起動中でないなら停止した日時
- PORTS : ホストポートとコンテナポートの接続状態
- NAMES : コンテナ名
削除
docker rm
コマンドで、指定されたIDのコンテナを削除できます。
コンテナを削除しても、そのコンテナの元となったイメージが残ることに注意してください。$ docker rm <docker ID> <docker ID> # または $ docker rm <docker Name> <docker Name>削除対象コンテナを複数指定すると、それらの一括削除が可能です。
$ docker rm <docker ID 1> <docker ID 2> <docker ID 1> <docker ID 2>起動していないコンテナを一括削除したい場合は、
docker container prune
で可能です。$ docker container prune WARNING! This will remove all stopped containers. Are you sure you want to continue? [y/N] y # 以下削除処理参考:dockerでいらないimage,container,networkを一括削除する
参考:Dockerのあれこれを断捨離するログの出力
dockerアプリで出たログを出力して見るには、
docker logs
コマンドを使います。
これはコンテナ停止中でもログ取得が可能です。$ docker logs <container ID> # または $ docker logs <container Name>docker内部に入る
docker内に実際に入ってコマンドを実行したいという場合は、以下のコマンドを実行します。
$ docker exec -it <container Name> /bin/bash # 以下、コンテナ内部 root@<container ID>:/#このように、このコマンドを使うと、ルートユーザーとしてログインすることになります。
コンテナ情報の確認
コンテナ情報一覧の取得
指定コンテナに関する全ての情報を取得するには、
docker inspect
コマンドを利用します。$ docker inspect <container ID>
しかし、如何せんこれでは全ての情報が一気に出力されるので、そこから自分の知りたい情報だけを探すのが大変です。そのため、知りたい情報だけをピンポイント出力するオプションをつけるのが一般的です。
コンテナに割り振られたIPアドレスの取得
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container ID> 172.18.0.6コンテナに割り振られたMACアドレスの取得
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' <container ID> 02:42:ac:12:00:06コンテナ内で設定された環境変数の取得
$ docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' <container ID> MYSQL_ROOT_USER=root MYSQL_ROOT_PASSWORD=pass MYSQL_DATABASE=sampledb PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin GOSU_VERSION=1.12 MYSQL_MAJOR=5.7 MYSQL_VERSION=5.7.30-1debian10参考:Docker-docs-ja公式ドキュメント inspect
参考:[Docker]docker inspcetコマンドでコンテナの情報を確認するdocker-compose
docker-compose.yml
に記述した設定を元にコンテナ群を起動したい場合は、以下のdocker-compose
コマンドを使います。コンテナ群の起動
以下のコマンドで、カレントディレクトリにある
docker-compose.yml
に沿ったコンテナ群が起動できます。$ docker-compose up Starting app_service1 ... done Starting app_service2 ... done # 以下コンテナログが流れるオプションをつけない状態では、デオフォルトでフォアグラウンドモードで起動され、以降ターミナルにコンテナログが流れてきます。
バックグラウンドで起動したい場合は、オプション
-d
をつければOKです。$ docker-compose up -d Starting app_service1 ... done Starting app_service2 ... done $ # バックグランド起動だと同ターミナルで引き続きコマンドラインの使用が可能また初回起動時には、これらのコンテナ群を繋ぐユーザ定義・ブリッジ・ネットワーク(app_default)も自動で作成されます。
(ネットワークについての詳細は後述)コンテナ群の停止
フォアグラウンドモードでの起動だった場合は、ターミナルで
Ctrl+C
を押すだけです。
バックグラウンドモードの場合は、docker-compose stop
コマンドを使います。$ docker-compose stop Stopping app_service1 ... done Stopping app_service2 ... done $イメージの再ビルド
コンテナアプリのソースコードを変えた場合は、もう一度コンテナをビルドしないと、現存するコンテナにソース変更が反映されません。
そのため、ソースコードの変更をコンテナに反映させるためには、docker-compose build
コマンドを使って再ビルドしてから起動という手順をたどる必要があります。$ docker-compose build # 以下ビルド処理の様子がログで流れる $ docker-compose up特定の一個のサービスだけbuildしたいなら、
docker-compose build <サービス名>
でサービスを指定すればOKです(サービス名はdocker-compose.ymlに記述したものです)。削除
docker-compose.yml
から作成したコンテナ群+ネットワークの削除は以下のコマンドで可能です。$ docker-compose down Removing app_service1 ... done Removing app_service2 ... done Removing network app_defaultただし、使用されていたイメージやボリュームは削除されないので、それも消したい場合は別途作業が必要です。
Images
既存のDockerfileからイメージを作成する
docker build
はDockerfileからimageを作成するコマンドです。
Dockerfileがあるディレクトリで実行すれば、-t
オプションでつけたタグ名のイメージが作成されます。# 最後の.はカレントディレクトリを意味するドットなので必要 $ docker build -t ImageA . $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ImageA latest 6c97772719d3 17 seconds ago 919MB (以下略)一覧の確認
docker images
で、現在存在するイメージを確認できます。$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ImageA latest 6c97772719d3 17 seconds ago 919MB
このコマンドで確認できる項目は以下の通り。
- REPOSITORY : イメージ名
- TAG : タグ名
- IMAGE ID : イメージのID
- CREATED : 作成日時
- SIZE : メモリ容量
repository・tagの追加
今あるイメージにリポジトリ・タグ名を新しく追加するためには以下のコマンドを使います。
(作った後も、<現repository>:<現tag>は残ります)$ docker tag <現repository>:<現tag> <新repository>:<新tag>
レジストリにpush
dockerレジストリにログインしている状態で以下のコマンドを実行することで、レジストリへのdockerイメージ登録ができます。
$ docker push <pushしたいイメージのrepository>:<pushしたいイメージのtag>
レジストリへのログイン方法は後述。
削除
docker rmi
コマンドで、指定されたIDのイメージを削除できます。$ docker rmi <image ID> Deleted: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b Deleted: sha256:9c27e219663c25e0f28493790cc0b88bc973ba3b1686355f221c38a36978ac63
現在存在しているコンテナに使われていないイメージを一括削除したい場合は、
docker image prune
コマンドを使います。$ docker image prune WARNING! This will remove all dangling images. Are you sure you want to continue? [y/N] y # 以下削除処理Registries
Dockerレジストリとは、dockerイメージの公開・保存・配布を行うサービスのことです。
(例)Docker Hub, ECRなどリポジトリにログイン
$ docker login --username <your-user-name> --password <your-password> <loginURL>リポジトリからログアウト
$ docker logout <loginURL>Networks
dockerのネットワーク概要
コンテナを単独で起動している分では、dockerのネットワークの仕組みがどうなっているのかはあまり意識しないことが多いでしょう。
ここでは、コマンドを紹介する前に、そもそもdockerネットワークがどういうものなのかを確認します。まず、dockerインストール時にすでに存在するデフォルトネットワークについて説明します。
上図引用:Docker Compose入門 (3) ~ネットワークの理解を深める~none
このネットワークを使うように指定されたコンテナには、外部のネットワークに繋ぐインターフェースが一切設置されません。
もちろんコンテナホストのPCと繋がるインターフェースも設置されないので、用途としてはネットワーク接続を必要としない開発環境を用意するときでしょう。host
この設定では、コンテナとホストがネットワークインターフェースを共有するものです。なので、コンテナのeth0とホストのeth0がそのまま繋がります。
これを利用すると、コンテナがホストマシンと同じIPアドレスを持つようになります。bridge
この設定では、ホストの任意のポートをコンテナのポートにマップすることで、コンテナ外部のネットワークに接続します。
例えば、先ほど紹介したdocker run -p 80:3000
というコマンドは、bridgeで「コンテナの3000番ポートをホストの80番ポートに繋ぐ」という設定をしていることになります。コンテナーホスト間のポートマッピングは、ホストマシンのLinuxカーネル内部に作られるイーサネット・ブリッジによって行われています(この仮想ブリッジにはdocker0という名前がついています)。
上図引用:第29回 Docker Networkingの基礎知識 標準的なネットワークを理解する (4/5)コンテナ内部とdocker0仮想ブリッジは、veth(Virtual Ethernet Tunnel)によって接続されています。vethペアのうち、コンテナ側のインターフェースは、コンテナ内ではeth0として振る舞います。残ったホスト側の方は、docker0ブリッジにつながるインターフェースとなります。
docker0ブリッジには、ホストマシンのeth0にも繋がっています。そのため、コンテナから外部への通信は、docker0ブリッジを経由し、そこでブリッジが提供するNAT機能を用いることで行うことになります。
ただし、このbridgeネットワークには名前解決機能がありません。
例えば、bridgeネットワークに同時にcontainer1
とcontainer2
というコンテナ2つが接続されているときに、container1
からcontainer2
に向けて通信するためには、宛先にcontainer2
という名前を使うことができず、container2
コンテナに付与されたプライベートIPアドレスをわざわざ調べてそれを使う必要があるということです。
コンテナに付与されるプライベートIPは、起動ごとにdockerが空いているIPを割り振るため不定です。そのため、コンテナ間通信に生のIPアドレスとそのまま使うのは避けるべきです。
そのため、同時に起動している他のコンテナと通信したいという場合は、次に挙げるdocker-conposeを利用したネットワークを利用します。参考:Docker-docs-ja公式ドキュメント Docker0 ブリッジのカスタマイズ
参考:Dockerのネットワークの仕組み
参考:Docker の基本学習 ~ Docker のネットワーク
参考:Docker network 概論docker-composeで作成されるネットワーク
上図引用:Docker Compose入門 (3) ~ネットワークの理解を深める~
docker-compose.yml
からコンテナを起動させた場合には、このようなユーザ定義・ブリッジ・ネットワークがデフォルトで作成されます。
仕組みとしては、上で挙げたbridgeネットワークと同じです。違いとしては、これにはDNS設定がされるので、bridgeネットワークでは不可能だったコンテナ間名での名前解決ができます。
参考:Docker入門(第五回)〜コンテナ間通信〜一覧確認
docker network ls
コマンドで現在存在するネットワーク設定一覧を確認できます。$ docker network ls NETWORK ID NAME DRIVER SCOPE af74802186be bridge bridge local a26bb8a73819 app_default bridge local c987a5c599df host host local 551c3f676ee0 none null localデフォルトネットワーク3つと、
docker-compose.yml
からできたユーザ定義・ブリッジ・ネットワークが1つ確認できました。
このコマンドで、以下のことがわかります。
- NETWORK ID: ネットワークID
- NAME: ネットワークの名前
- DRIVER: 元となったドライバ
- SCOPE: ネットワークのスコープ
ネットワークの状態の確認
コンテナと同様に、
inspect
コマンドでネットワークの詳細設定を確認することができます。$ docker network inspect <network Name>
削除
特定のネットワークを削除は、
docker network rm <name>
で可能です。$ docker network rm <network Name>Volumes
一覧確認
docker volume ls
でボリューム一覧が観れる。$ docker volume ls DRIVER VOLUME NAME local app_db-volume local app_redis-volumeボリュームの状態の確認
コンテナ・ネットワークと同様に、
inspect
コマンドで詳細設定を確認することができます。$ docker volume inspect <volume name> [ { "CreatedAt": "2020-06-20T16:44:05Z", "Driver": "local", "Labels": { "com.docker.compose.project": "app", "com.docker.compose.version": "1.23.2", "com.docker.compose.volume": "db-volume" }, "Mountpoint": "/var/lib/docker/volumes/app_db-volume/_data", "Name": "app_db-volume", "Options": null, "Scope": "local" } ]削除
特定のボリュームを削除するためには、
docker volume rm <name>
で可能。$ docker volume rm <volume Name>どこのコンテナにもアタッチされていないボリュームを一括削除するには、
docker volume prune
でできます。$ docker volume prune WARNING! This will remove all local volumes not used by at least one container. Are you sure you want to continue? [y/N] y # 以下削除処理
- 投稿日:2020-06-21T15:58:09+09:00
データサイエンス100本ノック(構造化データ加工編)の環境構築(Windows10)
はじめに
一般社団法人データサイエンティスト協会が、構造化データの加工を実践的に学べる無料の学習環境「データサイエンス100本ノック(構造化データ加工編)」をGitHubに公開しました。
本記事は、初学者の方でも無料の学習環境を構築できるように、導入手順の詳細を記載しました。
(構築する実行環境は下図になります。)
前提条件(Windows10)
- Docker Desktop for Windows
※起動しない場合は、Hyper-Vが「無効」になっている可能性があるので「有効」に設定。- Git for Windows
※インストール時のデフォルト設定である改行コード変更を「無効」に設定。
※本記事のコマンドはPowerShellで実行・検証済。> git config --global core.autocrlf input環境構築
学習環境用のディレクトリ(今回はdss)を作成し、100本ノックのリポジトリをクローンする。
その後、100本ノックのディレクトリ内に移動し、docker-compose
コマンドを使ってコンテナを作成する。(10分前後の時間がかかる。)
※環境構築中に警告のポップアップが表示される場合、DockerのローカルPCに対するアクセス権限がない可能性があるため「Share it」を選択してアクセス権限を付与する。> mkdir dss > cd dss > git clone https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess.git > cd 100knocks-preprocess > docker-compose up -d --build起動済みのコンテナを確認し、「dss-notebook」と「dss-postgres」の出力を確認できれば環境構築が成功。
> docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b35f99d4148a dss-notebook "tini -g -- start-no…" 23 seconds ago Up 22 seconds 0.0.0.0:8888->8888/tcp dss-notebook 3cb559c7f66d dss-postgres "docker-entrypoint.s…" 27 seconds ago Up 26 seconds 0.0.0.0:5432->5432/tcp dss-postgres使い方
ブラウザで下記のURLにアクセスすると、構築したJupyterの環境にアクセスできる。
http://localhost:8888
work
ディレクトリ配下に、構造化データ加工の演習問題の.ipynbファイルがある。
必要ライブラリのインポートや加工前のデータ取得は、最初のセルに記述済み。
演習問題に適した処理を、空欄のセルに入力して実行し、学習を進める。
演習問題の解答は、work/answer
ディレクトリ内に.ipynbファイルがある。
そのため、演習問題のファイルで回答した処理の正否を確認しながら作業可能。
学習環境の停止・起動
下記のコマンドで、構築した環境を停止可能。
> docker-compose stopまた、2回目以降に起動する場合は、下記のコマンドで起動可能。
> docker-compose start補足事項
構築した環境のレスポンスが遅い場合
Docker Desktop for WindowsのSettingsでResourcesでMemoryの値を変更してください。
推奨は、4.00GB以上です。
8888ポートが使用されている場合
もし、ローカルホストの8888ポートを他の開発環境(LAMPなど)で利用している場合は、docker-compose.ymlを下記のように変更(notebookのportsの値を変更)することで対応可能。
docker-compose.ymlnotebook: ports: - "888:8888"上記の場合、下記のURLでアクセス可能になる。
http://localhost:888まとめ
Windows10環境における、データサイエンス100本ノック(構造化データ加工編)の環境構築手順を記載いたしました。
上記の手順で不明点や疑問点等がありましたら、コメントいただけますと幸いです。参考リンク
- 投稿日:2020-06-21T15:57:10+09:00
ECSにdockerfileをpushしたときのメモ
AWS ECSリポジトリの作成後「プッシュコマンドの表示」をクリックすると下記が表示される。
pushのための実行コマンドが表示され、macOS/Linux もしくは Windowsと環境に合わせて選ぶように表示される。注意点
私はWindows環境だが、この表示される「Windows」とはホストOSを指すのではなく、使用するターミナルのことで、AWS Tools for Windows PowerShell を使用する場合という意味と思われる。
Windows環境下でもAWS Command Line Interface(AWS CTL)を使用している場合はmacOS/Linuxに表示されるコマンドを実行すること。
- 投稿日:2020-06-21T15:57:10+09:00
ECRにdockerfileをpushしたときのメモ
AWS ECRリポジトリの作成後「プッシュコマンドの表示」をクリックすると下記が表示される。
pushのための実行コマンドが表示され、macOS/Linux もしくは Windowsと環境に合わせて選ぶように表示される。注意点
私はWindows環境だが、この表示される「Windows」とはホストOSを指すのではなく、使用するターミナルのことで、AWS Tools for Windows PowerShell を使用する場合という意味と思われる。
Windows環境下でもAWS Command Line Interface(AWS CTL)を使用している場合はmacOS/Linuxに表示されるコマンドを実行すること。
- 投稿日:2020-06-21T15:11:53+09:00
ubuntuでdockerコンテナを使うときのメモ(datascience-notebook)
linux(ubuntu)でdockerコンテナのjupyter notebookを使うときのメモ
設定によって微妙に変わる。dockerコマンドに
sudo
をつけているがrootで実行する場合は必要なし。たぶんlinux以外の環境でもほぼ同じコマンドで使用できるとおもう。基本的には以下を参考にさせてもらう。ほぼコピペ。
https://qiita.com/y4m3/items/c2703d4e131e05084b7b
https://qiita.com/Brutus/items/a08c210b87ccb39379c2基本的な流れ
- コンテナをpullしてくる。
- コンテナを起動してコンテナ内のbash環境に入る。
- コンテナ内のjupyter認証用ハッシュを生成。
- 一旦コンテナから出る。
- 生成したハッシュを使用してコンテナ&jupyter起動。
- ブラウザ等でlocalhostに入る。
- ハッシュを入力。jupyterのトップ画面に入れたら成功。
コマンド
1.コンテナをpullしてくる。
sudo docker pull jupyter/datascience-notebookdatascience-notebookは数GBあるのでしばし待つ。
2.コンテナを起動してコンテナ内のbash環境に入る。
sudo docker run -it --rm jupyter/datascience-notebook /bin/bash-itオプションでコンテナに入る。 -rmオプションをつけるとコンテナから出たときにコンテナが削除される。イメージは残る。
3.コンテナ内のjupyter認証用ハッシュを生成。
python3 -c 'from notebook.auth import passwd;print(passwd())'と打つと
Enter password:
Verify password:と出るのでパスワードを入力する。
ハッシュが表示されるのでどこかにコピペして保存する。4.一旦コンテナから出る。
Ctrl+Dなどでコンテナから出る。5.生成したハッシュを使用してコンテナ&jupyter起動。
コンテナ内でrootが必要な場合は-u root
を付ける。rootの必要がなければ-u root
は外す。sudo docker run -d --name notebook -p 8888:8888 -u root jupyter/datascience-notebook start-notebook.sh --NotebookApp.password='sha1:生成したハッシュパスワード'6.ブラウザ等でlocalhostに入る。
http://localhost:88887.ハッシュを入力。jupyterのトップ画面に入れたら成功。
dockerの終了は
sudo docker stop コンテナIDdocker終了後、再度コンテナを開くとき
sudo docker start コンテナIDのあと、いつもどおりlocalhost:8888へアクセスすればOK。
メモ
jupyterのportは通常は8888となっていると思われるがローカル環境でjupyterを起動するなど8888のportが使用済みだったりするとdockerのjupyterを起動できない。
portを設定しないでjupyterを起動する場合、自動で使用していないportを使ったりしてくれるけどfirewallでそのportが開放されてないなどの状況もあるので、
portの使用状況は確認してから使う。以上。
- 投稿日:2020-06-21T15:11:53+09:00
linux(ubuntu)でdockerコンテナをpullしてjupyterを起動するまでのメモ
linux(ubuntu)でdockerコンテナをpullしてjupyterを起動するまでのメモ
設定によって微妙に変わる。dockerコマンドに
sudo
をつけているがrootで実行する場合は必要なし。たぶんlinux以外の環境でもほぼ同じコマンドで使用できるとおもう。基本的には以下を参考にさせてもらう。ほぼコピペ。
https://qiita.com/y4m3/items/c2703d4e131e05084b7b
https://qiita.com/Brutus/items/a08c210b87ccb39379c2基本的な流れ
- コンテナをpullしてくる。
- コンテナを起動してコンテナ内のbash環境に入る。
- コンテナ内のjupyter認証用ハッシュを生成。
- 一旦コンテナから出る。
- 生成したハッシュを使用してコンテナ&jupyter起動。
- ブラウザ等でlocalhostに入る。
- ハッシュを入力。jupyterのトップ画面に入れたら成功。
コマンド
1.コンテナをpullしてくる。
sudo docker pull jupyter/datascience-notebookdatascience-notebookは数GBあるのでしばし待つ。
2.コンテナを起動してコンテナ内のbash環境に入る。
sudo docker run -it --rm jupyter/datascience-notebook /bin/bash-itオプションでコンテナに入る。 -rmオプションをつけるとコンテナから出たときにコンテナが削除される。イメージは残る。
3.コンテナ内のjupyter認証用ハッシュを生成。
python3 -c 'from notebook.auth import passwd;print(passwd())'と打つと
Enter password:
Verify password:と出るのでパスワードを入力する。
ハッシュが表示されるのでどこかにコピペして保存する。4.一旦コンテナから出る。
Ctrl+Dなどでコンテナから出る。5.生成したハッシュを使用してコンテナ&jupyter起動。
コンテナ内でrootが必要な場合は-u root
を付ける。rootの必要がなければ-u root
は外す。sudo docker run -d --name notebook -p 8888:8888 -u root jupyter/datascience-notebook start-notebook.sh --NotebookApp.password='sha1:生成したハッシュパスワード'6.ブラウザ等でlocalhostに入る。
http://localhost:88887.ハッシュを入力。jupyterのトップ画面に入れたら成功。
dockerの終了は
sudo docker stop コンテナIDdocker終了後、再度コンテナを開くとき
sudo docker start コンテナIDのあと、いつもどおりlocalhost:8888へアクセスすればOK。
メモ
jupyterのportは通常は8888となっていると思われるがローカル環境でjupyterを起動するなど8888のportが使用済みだったりするとdockerのjupyterを起動できない。
portを設定しないでjupyterを起動する場合、自動で使用していないportを使ったりしてくれるけどfirewallでそのportが開放されてないなどの状況もあるので、
portの使用状況は確認してから使う。以上。
- 投稿日:2020-06-21T12:45:08+09:00
Docker で Terraform を実行する
準備
ここではVPCを作成してみます。
$ mkdir example $ cd example $ cat - << EOS > main.tf provider "aws" { version = "2.67.0" region = "ap-northeast-1" } resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" tags = { Name = "main" } } EOS実行
Terraform のバージョンの確認
$ docker run --rm hashicorp/terraform:0.12.26 --version Terraform v0.12.26フォーマット
$ docker run --rm -v $PWD:/work -w /work -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY hashicorp/terraform:0.12.26 fmt main.tf初期化
$ docker run --rm -v $PWD:/work -w /work -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY hashicorp/terraform:0.12.26 init実行計画の確認
$ docker run --rm -v $PWD:/work -w /work -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY hashicorp/terraform:0.12.26 plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. ------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_vpc.main will be created + resource "aws_vpc" "main" { + arn = (known after apply) + assign_generated_ipv6_cidr_block = false + cidr_block = "10.0.0.0/16" + default_network_acl_id = (known after apply) + default_route_table_id = (known after apply) + default_security_group_id = (known after apply) + dhcp_options_id = (known after apply) + enable_classiclink = (known after apply) + enable_classiclink_dns_support = (known after apply) + enable_dns_hostnames = (known after apply) + enable_dns_support = true + id = (known after apply) + instance_tenancy = "default" + ipv6_association_id = (known after apply) + ipv6_cidr_block = (known after apply) + main_route_table_id = (known after apply) + owner_id = (known after apply) + tags = { + "Name" = "main" } } Plan: 1 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.実行
$ docker run --rm -v $PWD:/work -w /work -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY hashicorp/terraform:0.12.26 apply -auto-approve aws_vpc.main: Creating... aws_vpc.main: Creation complete after 2s [id=vpc-xxxxxxxxxxxxxxxxx] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.破棄
$ docker run --rm -v $PWD:/work -w /work -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY hashicorp/terraform:0.12.26 destroy -auto-approve aws_vpc.main: Refreshing state... [id=vpc-xxxxxxxxxxxxxxxxx] aws_vpc.main: Destroying... [id=vpc-xxxxxxxxxxxxxxxxx] aws_vpc.main: Destruction complete after 1s Destroy complete! Resources: 1 destroyed.
- 投稿日:2020-06-21T12:21:03+09:00
local にデータベースの host も client も無い時に docker でのちょろっとした確認方法
手元の端末でちょろっとqueryの確認をしたいけど、そもそもローカルにclientすらインストールしていなかった時の不便を解決するための備忘録です。サーバ側のバージョン違いによる機能や挙動の確認は docker tag で制御する想定。
Postgresql
p11
,mydb
はご自由に変更をdocker exec
をすぐに実行してしまうとdocker run
の初期化が終わっておらずエラーが出ることがあるが、深呼吸して時間をおいて実行すれば動きます$ docker run --rm -d --name=p11 -e POSTGRES_USER=u -e POSTGRES_PASSWORD=p -e POSTGRES_DB=mydb postgres:11 $ docker exec -it p11 psql -h localhost -U u -d mydb # inside docker exit; # outside docker $ docker stop p11MySQL
m8
,mydb
はご自由に変更をdocker run -it --rm -d --name=m8 -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -e MYSQL_DATABASE=mydb mysql:8 docker exec -it m8 mysql -h localhost mydb # inside inside docker exit; # outside docker docker stop m8SQLite
- 公式dockerイメージは見つからなかった。
- 出力をカンマ区切りにするためには
$'\t'
を,
に変更すればよいdocker run -it --rm nouchka/sqlite3 sqlite3 -header -separator $'\t' sqlite> .q
- 投稿日:2020-06-21T12:01:41+09:00
Dockerコンテナ上でAnsibleを動かす
はじめに
DockerコンテナにAnsibleをインストールし、別のLinuxサーバ(Ubuntu)にファイルをコピーするところまでをやってみたいと思います。DockerをインストールするサーバのOSはAmazon Linux 2です。
Dockerインストール
# yumを更新 $ sudo yum -y update # Dockerをインストール $ sudo yum install -y docker # Docker デーモンを起動 $ sudo service docker start # dockerコマンドをsudoなしで実行できるように設定 $ sudo usermod -aG docker ec2-user # docker自動起動を有効化 $ sudo systemctl enable docker # 設定反映のためsshで再接続 $ exitコンテナ作成
Dockerfile作成
$ sudo mkdir docker-demo $ cd docker-demo $ sudo vim DockerfileAnsibleを動かすためpython3を使用します。
WORKDIRは後ほど作成するAnsibleのファイルを置くディレクトリを指定します。
今回はsshのパスワード認証でUbuntuサーバに接続するため、sshとsshpassをインストールします。DockerfileFROM python:3 WORKDIR /usr/src/app RUN pip install ansible==2.9 RUN apt-get update && apt-get install -y \ ssh \ sshpassDockerfileからイメージを構築
イメージ名を「test-ansible」としています。$ docker build -t test-ansible .Ansible環境作成
Ansibleのファイルを保存するディレクトリ作成
$ sudo mkdir -p /usr/src/app $ cd /usr/src/appinventoryファイルとplaybook.ymlを作成
※今回はデモのため、ディレクトリ構成やPlaybookはAnsibleベストプラクティスに則っていませんinventory[nodes] testserver ansible_host=10.0.1.100 ansible_connection=ssh [nodes:vars] ansible_port=22 ansible_user=test-user ansible_ssh_pass=p@ssW0rdplaybook.yml- name: copy files - hosts: nodes become: yes become_user: root become_method: sudo gather_facts: no vars: ports: 22 copy: src: /usr/src/app/test.txt dest: /home/ubuntu owner: root group: root mode: 0644同じディレクトリに今回コピーするファイルを作成
$ sudo vim test.txttest.txttest fileコンテナ起動
/usr/src/appディレクトリでdocker runコマンドを実行
オプションの説明は以下の通り。
-it:コンテナ上で擬似ターミナルを割り当て、標準入力を開き続ける
-v:ホストのディレクトリをコンテナにマウントする-vオプションにより、コンテナ上からAnsibleファイルが見えるようになります。
$ docker run -it -v $(pwd):/usr/src/app test-ansible /bin/bash # known_inventory にフィンガープリントを記録する処理の無効化 $ export ANSIBLE_HOST_KEY_CHECKING=Falseコンテナ上でansible-playbookコマンド実行
$ ansible-playbook -i inventory ./playbook.yml PLAY [nodes] ************************************************************************************************************************************************ TASK [copy files] ******************************************************************************************************************************************* ok: [testserver] PLAY RECAP ************************************************************************************************************************************************** testserver : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0結果
Ubuntuサーバ上でファイルがコピーされたことを確認
$ cat test.txt test file
- 投稿日:2020-06-21T10:54:01+09:00
Docker+JupyterLabで決定木モデルの可視化(graphviz/dtreeviz)
概要
決定木についての詳細は記載しませんが、決定木によって生成されたモデルの可視化で一般的なのがgraphvizです。これをDocker+JuptyerLabの環境で使おうとしたら微妙にハマった部分があったので、やり方をまとめておきます。またgraphvizではなく、より分かり易い可視化でdtreevizが便利だったのでそちらも記載します。
環境
以下を参考にDockerでJupyterLabが使える状態を前提とします。
Dockerで起動したJupyterLabでvimキーバインドを使うDockerfile
Dockerfileに以下追記してビルドし直す事でgraphvizとdtreevizが使えるようになりました。
DockerfileRUN pip install pydotplus RUN pip install dtreeviz RUN apt-get dist-upgrade RUN apt-get update RUN apt-get install -y build-essential graphviz-dev graphviz pkg-config RUN pip install graphvizgraphvizはPythonのライブラリとLinuxのライブラリで両方入れる必要があり、
Linuxライブラリの方がなかなかうまく入ってくれなかったですが、上記でうまくできました。Dockerfileの全体についてはこちらにもまとめてあります。
https://github.com/hikarut/Data-Science/blob/master/Dockerfileモデルの可視化
graphviz
- 1行目:条件式
- 2行目:ジニ係数
- 3行目:ノードのサンプル数(サンプル割合)
- 4行目:クラス毎のサンプル数(サンプル割合)
dtreeviz
ソース
https://github.com/hikarut/Data-Science/blob/master/notebooks/decisionTree/sample.ipynb参考
- 投稿日:2020-06-21T10:46:01+09:00
DockerコンテナのホストでGUIを起動する
環境
Ubuntu20.04
Docker 19.031.ホストでの準備
下記のコマンドでX WindowサーバがContainer内からの接続を受け入れるように設定します。
xhost local:2.コンテナを起動
GUIを使えるようにオプションを設定しコンテナ起動する。
下記のコマンドを実行するとpython3.8.3が使えるコンテナをインタラプタモードで起動する。
コマンドのオプションの説明
-e DISPLAY=$DISPLAY
: GUIを転送するX11サーバーのアドレスを設定--net host
: コンテナ上のX11クライアントがサーバーにアクセスできるよう、コンテナのネットワーク設定をホストと共有するdocker run -v $PWD:/working -e DISPLAY=$DISPLAY --net host --name python -it python:buster /bin/bash3.GUIが使えるかの確認
コンテナのbash上で下記のコマンドを実行してGUIが使えるかを確認
1.xeyesを使う
apt update apt install x11-apps xeyes2.matplotlibを使う
test.pyimport matplotlib.pyplot as plt img=list([[2,3,4],[5,6,7]]) plt.imshow(img, cmap='Greys') plt.show() #画像を表示させる上記のコードをpythonで実行
参照
- 投稿日:2020-06-21T08:43:37+09:00
Dockerで構築したWebアプリケーションの常時SSL化
はじめに
趣味で、RaspberrypiにDocker環境を構築して、redmineやWodpressを運用しています。それらのWebアプリケーションをSSL化したいと思います。
環境は下記の通り。
- HW:Raspberry pi 4 model B
- OS:Ubuntu 19.10
Letsencryptの導入
SSL証明書は、Letsencryptを利用して発行します。RaspberrypiのCPUはARMアーキテクチャなので、使えるDockerイメージが限られます。今回は、ARMで利用できる「linuxserver/letsencrypt」を利用します。
docker-composeは下記の通り。詳しい説明は、作者のgithubのREADMEを読んでください。
https://github.com/linuxserver/docker-letsencrypt/blob/master/README.mdservices: letsencrypt: image: linuxserver/letsencrypt container_name: letsencrypt cap_add: - NET_ADMIN environment: - PUID=1000 - PGID=1000 - TZ=Asia/Tokyo - URL=asubee.local - SUBDOMAINS=wordpress,redmine - VALIDATION=http ports: - "80:80" - "443:443" restart: unless-stopped volumes: - letsencrypt-config:/config volumes: letsencrypt-config: external: trueこのdocker-composeでは、「asubee.local」ドメインに、追加でサブドメインとして「wordpress」「redmine」を追加しています。事前に、「asubee.local」のDNS登録とワイルドカードの有効化をしておきます。Dynamic DNSのサービスがインターネット上でたくさんあるので、好きなドメインを取得してください。
証明書の取得の際には、
http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>
が外部からアクセスできる状態にする必要があります。事前にLinuxのFW設定や、ルータのポート変換の設定をしておきましょう。LinuxのFW設定
Ubuntuは、「ufw」というFWの機能があります。事前に80番と443番の穴あけをしておきます。
$sudo ufw allow 80 Rule added Rule added (v6) $sudo ufw allow 443 Rule added Rule added (v6) $sudo ufw status To Action From -- ------ ---- 80 ALLOW Anywhere 443 ALLOW Anywhere 22 ALLOW 192.168.11.0/24 80 (v6) ALLOW Anywhere (v6) 443 (v6) ALLOW Anywhere (v6)ルータの設定
ルータには、ポート変換の設定をしておきます。今回、raspberrypiのIPアドレスは「192.168.11.10」を設定してるので、80番、443番に来たリクエストをすべてraspberrypiに転送する設定をしました。
letsencryptの起動
下記コマンドでletsencryptのコンテナを起動します。「Server ready」と表示されていれば起動完了です。
$ docker-compose up -d letsencrypt | Variables set: letsencrypt | PUID=1000 letsencrypt | PGID=1000 letsencrypt | TZ=Asia/Tokyo letsencrypt | URL=llasuka.local letsencrypt | SUBDOMAINS=wordpress,redmine letsencrypt | EXTRA_DOMAINS= letsencrypt | ONLY_SUBDOMAINS=false letsencrypt | DHLEVEL=2048 letsencrypt | VALIDATION=http letsencrypt | DNSPLUGIN= letsencrypt | EMAIL= letsencrypt | STAGING= (省略) letsencrypt | [cont-init.d] 50-config: exited 0. letsencrypt | [cont-init.d] 99-custom-files: executing... letsencrypt | [custom-init] no custom files found exiting... letsencrypt | [cont-init.d] 99-custom-files: exited 0. letsencrypt | [cont-init.d] done. letsencrypt | [services.d] starting services letsencrypt | [services.d] done. letsencrypt | Server readyリバースプロキシの設定
letsencryptは、nginxで動いているので、設定を追加してリバースプロキシとして機能するように設定します。
リバースプロキシについては、下記URLを参照してください。
https://github.com/linuxserver/reverse-proxy-confs/blob/master/README.md重要なディレクトリは下記の通り。
/config/nginx
nginxの設定ファイルが入っているディレクトリ/config/nginx/site-confs
追加のnginxの設定を格納するディレクトリ/config/nginx/proxy-confs
proxy設定例がたくさん格納されているディレクトリ。この配下にあるファイル名の「.sample」を削除するだけで設定が有効になります/config/log/nginx
nginxのアクセスログの格納場所リバースプロキシの設定を記述したredmine.confとwordpress.confを作成し、
/config/nginx/site-confs/
配下に格納します。記述方法は、/config/nginx/proxy-confs
配下のサンプルを参考にしています。redmine.conf
redmineは、raspberryiのポート3000番でアクセスできるように設定しています。基本的な設定は、すでにconfigが存在しているので、includeすることで最小限の記述だけでリバースプロキシが設定できます。
server { listen 443 ssl; listen [::]:443 ssl; server_name redmine.*; include /config/nginx/ssl.conf; client_max_body_size 0; location / { include /config/nginx/proxy.conf; proxy_pass http://192.168.11.10:3000; proxy_redirect off; } }wordpress.conf
wordpressも同様に設定をします。Wordpressは8080番でアクセスできるように設定しています。
server { listen 443 ssl; listen [::]:443 ssl; server_name wordpress.*; include /config/nginx/ssl.conf; client_max_body_size 0; location / { include /config/nginx/proxy.conf; proxy_pass http://192.168.11.10:8080; proxy_redirect off; } }(参考)コンテナの起動状態
raspberrypiには、5つのコンテナが起動しています。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 196aeda36993 linuxserver/letsencrypt "/init" 19 minutes ago Up 19 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp letsencrypt fd2cd08a15d9 wordpress:latest "docker-entrypoint.s…" 2 days ago Up 38 hours 0.0.0.0:8080->80/tcp withdb_wordpress_1 cd2fb1865f32 mariadb "docker-entrypoint.s…" 2 days ago Up 38 hours 3306/tcp withdb_wordpress-mariadb_1 ca2df570bed6 withdb_redmine "/docker-entrypoint.…" 5 days ago Up 38 hours 0.0.0.0:3000->3000/tcp withdb_redmine_1 f8c4f8c289b0 mariadb "docker-entrypoint.s…" 5 days ago Up 38 hours 3306/tcp withdb_mariadb_1参考サイト
- 投稿日:2020-06-21T03:35:03+09:00
Dockerファイルがビルドできなかったのでコンパイラをいじめる
TL;DR
- ある環境でビルドできたDockerfileが別の環境でビルドできなかったのは、メモリ制限のせいだった
はじめに
理研シミュレータというシミュレータがあります。
これは、「京」の次のスーパーコンピュータ「富岳」が採用しているアーキテクチャ「Fujitsu A64FX」のシミュレータです。Gem5というアーキテクチャシミュレータがあり、それにARM AArch64を実装したものです。
これを使うと、AArch64のプロセッサレベルでのシミュレートができるのですが、ビルドに結構手間がかかります。なので、その「手間」をまとめたDockerファイルを作りました。
Dockerファイルはこんな感じです。
FROM ubuntu:18.04 MAINTAINER kaityo256 ENV USER user ENV HOME /home/${USER} ENV SHELL /bin/bash RUN useradd -m ${USER} RUN gpasswd -a ${USER} sudo RUN echo 'user:userpass' | chpasswd RUN apt-get update && apt-get install -y \ g++ \ g++-8-aarch64-linux-gnu \ git \ m4 \ python-dev \ scons \ sudo \ vim \ qemu-user-binfmt \ zlib1g-dev USER ${USER} RUN cd ${HOME} \ && mkdir build \ && cd build \ && git clone --depth 1 https://github.com/RIKEN-RCCS/riken_simulator.git RUN cd ${HOME} \ && cd build/riken_simulator \ && sed -i "369,372s:^:#:" SConstruct \ && scons build/ARM/gem5.opt -j 20 RUN cd ${HOME} \ && git clone https://github.com/kaityo256/aarch64env.git RUN cd ${HOME} \ && echo alias gem5=\'~/build/riken_simulator/build/ARM/gem5.opt ~/build/riken_simulator/configs/example/se.py -c\' >> .bashrc \ && echo alias ag++=\'aarch64-linux-gnu-g++-8 -static -march=armv8-a+sve\' >> .bashrcたいしたことはしていません。ビルドで僕が詰まったところをちょこちょこ修正してからビルドしているだけです。Riken Simulatorはビルドにえらい時間がかかるのですが、手元に20コアのLinuxマシンがあったので、sconsに
-j 20
を指定して20並列でビルドしています。さて、このDockerファイルがビルドできない、という連絡が来ました。Dockerって後ろがMacだろうがWindowsだろうかLinuxだろうが同じ環境を作ってくれるものなのに、環境依存性があるとは何事ぞ?と思って調査を始めました。こういう調査ログは、たまに誰かの役に立つこともあるので残しておきます。
調査ログ
並列ビルドとキャッシュ
まず疑うのはキャッシュです。Dockerはビルドする時にキャッシュするため、作業の手順によってはおかしなことがおきることがあります。まずは、ローカルで作業した人に
--no-cache
の指定をお願いしましたが、やはりこけたという連絡が来ます。次に疑ったのは自分のビルドです。キャッシュのせいでビルドできたけれど、実はクリーンビルドしたらこけるのではないかと思い、Linuxマシンで
--no-cache
を指定してビルドしなおします。普通にビルドできます。
-j 20
を-j 4
に減らしてもらってもこける、という報告がきます。また、並列ビルドをやめたら、こけなくはなったがビルドが途中で止まる、という連絡が来ました。ローカルでのチェック
とりあえず、自分でもローカルマシンで試すことにしました。まずは
-j 20
のままビルドします。こけます。
internal compiler errorさんお久しぶりです。整数を419378回インクリメントした時以来ですね。internal compiler error、略してICEですが、普通に生きていればあまり見かけないと思います。・・・というようなことをあるところで口走ったら、「え?ICEなんて日常的に見ますよね?」みたいな反応があったのでC++ガチ勢は怖いなと思いました。閑話休題。
とりあえず4コアしかないマシンで20並列するのもアレなんで、
-j 4
でやり直してみます。やっぱりこけますね。
さて、ビルドに失敗する理由がICEである、ということから、メモリ不足を疑います。
まず、LinuxサーバでDockerfileをビルド中に
docker stats
で利用メモリを確認します。おおぅ、2.9GB使ってますね。
次に、ローカルのDockerのメモリ制限を見てみましょう。
Memoryが2.00GB。これですね。
メモリが潤沢にあるLinuxマシンで、2GBのメモリ制限をかけてビルドしなおしてみましょう。
docker build -t kaityo256/aarch64env:memtest -m 2gb . --no-cacheはい、こけましたね。メモリ不足が原因と確定です。ローカルマシンでビルドに失敗した人には、DockerのSettingsのResourcesでメモリ上限を増やして再度試すようお願いし、ちゃんとビルドできることが確認できてめでたしでした。
どこでこけたか?
さて、Dockerファイルがビルドできない問題はこれで解決としても、「なんでこんなにメモリを消費したのか」は気になります。20並列はともかく、4並列でもこけて、シリアルビルドだとこけないけどビルドが止まってしまう、ということは、一つのファイルをコンパイルするのに2GB以上を使うファイルがあるはずです。それを調べてみましょう。
まずは、ビルド直前のイメージを作ります。
FROM ubuntu:18.04 MAINTAINER kaityo256 ENV USER user ENV HOME /home/${USER} ENV SHELL /bin/bash RUN useradd -m ${USER} RUN gpasswd -a ${USER} sudo RUN echo 'user:userpass' | chpasswd RUN apt-get update && apt-get install -y \ g++ \ g++-8-aarch64-linux-gnu \ git \ m4 \ python-dev \ scons \ sudo \ vim \ qemu-user-binfmt \ zlib1g-dev USER ${USER} RUN cd ${HOME} \ && mkdir build \ && cd build \ && git clone --depth 1 https://github.com/RIKEN-RCCS/riken_simulator.git RUN cd ${HOME} \ && cd build/riken_simulator \ && sed -i "369,372s:^:#:" SConstructこのイメージをビルドします。
docker build -t kaityo256/aarch64before .そして、2GBの制限をかけた上でコンテナを起動し、アタッチします。
docker run -it -u user -m 2gb kaityo256/aarch64before
user
は、作業用に作ったユーザアカウントです。さて、とりあえず並列ビルドしてこけることを確認します。cd cd build cd riken_simulator scons build/ARM/gem5.opt -j 20もう一枚ターミナルを開いて、
docker stats
でリソースを監視します。メモリのリミットが2GiBになっています。で、こけたところで、続けて2並列でビルドしましょう。
scons build/ARM/gem5.opt -j 2
あるところでメモリを使い切り、ビルドが進まなくなります。
ここでビルドを止めます。どこで止まったか調べるため、
scons --dry-run
しましょう。$ scons build/ARM/gem5.opt --dry-run (snip) [ CXX] ARM/arch/arm/generated/inst-constrs-3.cc -> .o [ CXX] ARM/arch/arm/generated/generic_cpu_exec_1.cc -> .o [ CXX] ARM/arch/arm/generated/generic_cpu_exec_2.cc -> .o [ CXX] ARM/arch/arm/generated/generic_cpu_exec_3.cc -> .o [ CXX] ARM/arch/arm/generated/generic_cpu_exec_4.cc -> .o [ CXX] ARM/arch/arm/generated/generic_cpu_exec_5.cc -> .o [ CXX] ARM/arch/arm/generated/generic_cpu_exec_6.cc -> .o (snip)ビルドできていないターゲットの先頭は
ARM/arch/arm/generated/inst-constrs-3.o
です。こいつを単独でビルドしてみましょう。
scons build/ARM/arch/arm/generated/inst-constrs-3.oもう一枚のターミナルで
docker stats
で監視すると、メモリを使い切っていることがわかります。メモリが十分にあればビルドできるはずなので、このファイルをビルドするのにどれくらいのメモリが必要なのか調べてみましょう。
一度Dockerコンテナから出ます。そして、ビルド直前のイメージからやりなおします。こういうことができるのがDockerの便利なところですね。今度はメモリ制限をかけません。
docker run -it -u user kaityo256/aarch64before利用メモリを調べるために
time
をインストールします。sudo apt install -y time
time -v
をかませて、問題のファイルをビルドしてみましょう。普通にtime
とするとシェルのtimeが使われてしまうため、フルパスで指定します。$ cd $ cd build/riken_simulator/ $ /usr/bin/time -v scons build/ARM/arch/arm/generated/inst-constrs-3.o (snip) scons: done building targets. Command being timed: "scons build/ARM/arch/arm/generated/inst-constrs-3.o" User time (seconds): 117.09 System time (seconds): 10.16 Percent of CPU this job got: 101% Elapsed (wall clock) time (h:mm:ss or m:ss): 2:05.54 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 2686200 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 2598152 Voluntary context switches: 10887 Involuntary context switches: 963 Swaps: 0 File system inputs: 0 File system outputs: 177568 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0注目すべきは「Maximum resident set size」です。2686200 (kbytes)、つまりたった一つのファイルのコンパイルに2.56GB使ってますね。このファイルが原因と判明しました。
なぜそんなにメモリを食うのか
さて、問題のファイルが
build/ARM/arch/arm/generated/inst-constrs-3.cc
であると判明しました。inst-constrs-1.cc
やinst-constrs-2.cc
という似たファイルもありますが、同様にtime -v
で調べても(まぁまぁ使いますが)死ぬほどメモリを使っている、という感じはしません。では、このファイルをどうやってビルドしているのか確認しましょう。まず、このファイル関連をクリーンします。SConsは-cをつけると関連ファイルを消してくれます。
scons -c build/ARM/arch/arm/generated/inst-constrs-3.o
次に、dry runでビルドコマンドを確認しましょう。
$ scons --dry-run build/ARM/arch/arm/generated/inst-constrs-3.o (snip) scons: Building targets ... [ISA DESC] ARM/arch/arm/isa/main.isa -> generated/decoder-g.cc.inc, generated/decoder-ns.cc.inc, generated/decode-method.cc.inc, generated/decoder.hh, generated/decoder-g.hh.inc, generated/decoder-ns.hh.inc, generated/exec-g.cc.inc, generated/exec-ns.cc.inc, generated/max_inst_regs.hh, generated/decoder.cc, generated/inst-constrs-1.cc, generated/inst-constrs-2.cc, generated/inst-constrs-3.cc, generated/generic_cpu_exec_1.cc, generated/generic_cpu_exec_2.cc, generated/generic_cpu_exec_3.cc, generated/generic_cpu_exec_4.cc, generated/generic_cpu_exec_5.cc, generated/generic_cpu_exec_6.cc [ CXX] ARM/arch/arm/generated/inst-constrs-3.cc -> .o scons: done building targets.情報ゼロです。SConsは通常、ビルドコマンドを表示してくれますが、SConstructの設定で消されているようです。見てみましょう。
if GetOption('verbose'): def MakeAction(action, string, *args, **kwargs): return Action(action, *args, **kwargs) else: MakeAction = Action main['CCCOMSTR'] = Transform("CC") main['CXXCOMSTR'] = Transform("CXX") main['ASCOMSTR'] = Transform("AS") main['ARCOMSTR'] = Transform("AR", 0) main['LINKCOMSTR'] = Transform("LINK", 0) main['SHLINKCOMSTR'] = Transform("SHLINK", 0) main['RANLIBCOMSTR'] = Transform("RANLIB", 0) main['M4COMSTR'] = Transform("M4") main['SHCCCOMSTR'] = Transform("SHCC") main['SHCXXCOMSTR'] = Transform("SHCXX")ここですね。オプションに
--verbose
がついていない場合、g++によるビルドが[ CXX]
とだけ表示されるようになっているようです。というわけで
--verbose
をつけてみましょう。$ scons --verbose build/ARM/arch/arm/generated/inst-constrs-3.o (snip) g++ -o build/ARM/arch/arm/generated/inst-constrs-3.o -c -std=c++11 -pipe -fno-strict-aliasing -Wall -Wundef -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-error=suggest-override -g -O3 -DTRACING_ON=1 -Iext/pybind11/include -Ibuild/nomali/include -Ibuild/libfdt -Ibuild/libelf -Ibuild/iostream3 -Ibuild/fputils/include -Ibuild/drampower/src -Iinclude -Iext -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 -Iext/googletest/include -Ibuild/ARM build/ARM/arch/arm/generated/inst-constrs-3.ccコンパイルコマンドがわかりました。多数のインクルードファイルに依存しているようなので、それらを全部インクルードしたファイルを作りましょう。
g++ -E
を使います。g++ -E -std=c++11 -pipe -fno-strict-aliasing -Wall -Wundef -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-error=suggest-override -g -O3 -DTRACING_ON=1 -Iext/pybind11/include -Ibuild/nomali/include -Ibuild/libfdt -Ibuild/libelf -Ibuild/iostream3 -Ibuild/fputils/include -Ibuild/drampower/src -Iinclude -Iext -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 -Iext/googletest/include -Ibuild/ARM build/ARM/arch/arm/generated/inst-constrs-3.cc > expanded.ccこれで
expanded.cc
という、単独でコンパイルできるファイルができました。コンパイルして利用メモリを確認してみましょう。$ /usr/bin/time -v g++ -O3 -S expanded.cc Command being timed: "g++ -O3 -S expanded.cc" User time (seconds): 73.39 System time (seconds): 1.48 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 1:15.06 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 1993036 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 1390330 Voluntary context switches: 4 Involuntary context switches: 94 Swaps: 0 File system inputs: 0 File system outputs: 61456 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 02GBくらい使っています。元のビルドオプションには
-g
もついていたため、さらにメモリを食っていましたが、外しても結構あります。行数を見てみましょうか。$ wc expanded.cc 203875 533178 5907751 expanded.cc20万行ですか。なかなかですね。
とりあえず、
g++ -E
で生成したファイルの常として、空白行や#
で始まる行が多いため、それらを削除しましょう。sed -i '/^$/d' expanded.cc sed -i '/^#/d' expanded.ccこれで15万行になりますが、まだ多いです。気合で中身を見てみると、ARMのISAを定義しているところが大部分で、最後の方に命令のデコーダ関連と思しきコードがあります。例えばこんなのです。
static StaticInstPtr decodeNeonThreeRegistersSameLength(ExtMachInst machInst) { ...なんか三個のレジスタで同じ長さの何かをどうにかするコードなんでしょうね。
で、ここからは気合です。
#if 0
~#endif
で囲ってはコンパイルして、どの部分がメモリを食うのかを調べます。すると、最後のデコーダまわりで、一番最後の名前空間namespace ArmISAInst { ... }1万3千行のコンパイルにメモリを食っていることがわかりました。全体が15万5千行あるので、10%未満ですね。実はそのコードの前あたりでテンプレートが大量にあるので、テンプレート展開が原因だと疑っていたのですが、
namespace ArmISAInst
で囲まれた問題箇所にはテンプレートまわり怪しいところがありません。その代わり、やたらとswitch、caseがありました。特に、多段switchがあるのが気になります。case 0x2: case 0x3: { uint32_t imm12 = bits(machInst, 21, 10); uint8_t shift = bits(machInst, 23, 22); uint32_t imm; if (shift == 0x0) imm = imm12 << 0; else if (shift == 0x1) imm = imm12 << 12; else return new Unknown64(machInst); switch (opc) { case 0x0: return new AddXImm(machInst, rdsp, rnsp, imm); case 0x1: return new AddXImmCc(machInst, rdzr, rnsp, imm); case 0x2: return new SubXImm(machInst, rdsp, rnsp, imm); case 0x3: return new SubXImmCc(machInst, rdzr, rnsp, imm); } }fall throughがあるのも気になりますね。巨大なswitch文、特に多段switchがあることがメモリを使う原因なのでしょうか?
多段switch
というわけで、多段switch文を吐くスクリプトを組んで、実際にコンパイルしてメモリを食うことを確認してみましょう。
こんなRubyスクリプトを書きます。
if ARGV.size != 2 puts "usage: ruby switch.rb max num" exit end $max_level = ARGV[0].to_i num = ARGV[1].to_i def print_switch(num, level) indent = " "*level + " " puts "#{indent}switch(i#{level}){" num.times do |i| puts "#{indent} case #{i}:" if level < $max_level print_switch(num, level+1) else puts "#{indent} return #{i};" end end puts "#{indent}}" end arg = Array.new($max_level+1) { |i| "int i"+i.to_s }.join(",") puts "int func(#{arg}){" print_switch(num, 0) puts "}"これは、n段m行のswitchを持つコードを吐くスクリプトです。2段2行ならこんな感じです。
$ ruby switch.rb 1 2 int func(int i0,int i1){ switch(i0){ case 0: switch(i1){ case 0: return 0; case 1: return 1; } case 1: switch(i1){ case 0: return 0; case 1: return 1; } } }nを指定しているのにn+1段になっているのに後から気が付きましたが、気にしないことにします。まずは5段10行から試しましょうか。
$ ruby switch.rb 4 10 > test.cpp $ /usr/bin/time -v g++ -O3 -S test.cpp Command being timed: "g++ -O3 -S test.cpp" User time (seconds): 48.12 System time (seconds): 0.96 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:49.26 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 642564 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 199589 Voluntary context switches: 0 Involuntary context switches: 0 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0627MBですか。もう一声って感じですかね。5段12行でいきましょう。
$ ruby switch.rb 4 12 > test.cpp $ /usr/bin/time -v g++ -O3 -S test.cpp Command being timed: "g++ -O3 -S test.cpp" User time (seconds): 301.32 System time (seconds): 3.32 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 5:05.30 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 1263288 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 569445 Voluntary context switches: 0 Involuntary context switches: 0 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0コンパイルに5分かかって、メモリも1.2GiB使ってますね。ちなみにこのコードは56万行で、switchは5段のが一つ、元のコードは1万3千行で、switchも2段くらいのが多数という違いがあります。でもまぁ、テストコードは単に整数をreturnしてますが、元のコードはなんかオブジェクトを作ってreturnとかしてたので、その絡みで余計にメモリを食ったのかな、という気がします。本当にそうかは知りませんが。
まとめ
Dockerファイルがビルドできない、という連絡を受け、その原因がメモリ不足であること、その原因となるファイルの特定とかやっているうちに、いつのまにかコンパイラをいじめていました。なぜだ?
- 投稿日:2020-06-21T03:12:46+09:00
linux alias 設定メモ./bashrc
linuxのaliasってどうやって設定すんの?
二種類ある。
- 一時的な設定
- 恒久的な設定一時的な設定
これだとログアウトしたりすると消えてしまう。
shellalias name='value'恒久的な設定
homeディレクトリ配下に
.bashrc
ってファイルが隠れているので追記する。.bashrc# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions ★ここに追記 #例 alias la="ls -a"alias確認方法
現在登録されているエイリアスは
alias
コマンドで確認。[ec2-user@~]$ alias alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' alias l.='ls -d .* --color=auto' alias la='ls -a' alias ll='ls -l --color=auto' alias ls='ls --color=auto'経緯
dockerコマンドにエイリアスを設定したかった
同じイメージ名で
docker-compose build
すると<none>:<none>
という空のdockerのイメージファイルができてしまう。
上書きしてほしいところだが、いちいち消すしかないみたい。
だが、削除するために下記のコマンドを毎回打つのは面倒。shelldocker images -f dangling=true -q | xargs docker rmiコマンドメモ
command detail docker -f フィルタ docker -q ID抽出 xargs <commnad> <command> [パイプされた引数1] [引数2] [引数3] ... docker rmi <imageID> docker イメージ削除 なので
rmidang
というエイリアスにする。
dockerのconfigにエイリアスはないようなので、bashに追加することにした。gitみたいに用意してほしい。
ちなみにdangling
は宙ぶらりんの意。結果
.bashrc# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions alias la="ls -a" #docker ##remove dangling images alias rmidang="docker images -f dangling=true -q | xargs docker rmi"参考
世の中のエンジニアのalias設定
https://qiita.com/reireias/items/d906ab086c3bc4c22147
aliasと関数で幸せになろう
https://qiita.com/belion_freee/items/528ff57b920d559abf3d
aliasの引数使いたいときは関数を使うbash起動時の設定ファイル実行順序
- 投稿日:2020-06-21T03:12:46+09:00
linux alias 設定メモ
linuxのaliasってどうやって設定すんの?
二種類ある。
- 一時的な設定
- 恒久的な設定一時的な設定
これだとログアウトしたりすると消えてしまう。
shellalias name='value'恒久的な設定
homeディレクトリ配下に
.bashrc
ってファイルが隠れているので追記する。.bashrc# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions ★ここに追記 #例 alias la="ls -a"alias確認方法
現在登録されているエイリアスは
alias
コマンドで確認。[ec2-user@~]$ alias alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' alias l.='ls -d .* --color=auto' alias la='ls -a' alias ll='ls -l --color=auto' alias ls='ls --color=auto'経緯
dockerコマンドにエイリアスを設定したかった
同じイメージ名で
docker-compose build
すると<none>:<none>
という空のdockerのイメージファイルができてしまう。
上書きしてほしいところだが、いちいち消すしかないみたい。
だが、削除するために下記のコマンドを毎回打つのは面倒。shelldocker images -f dangling=true -q | xargs docker rmiコマンドメモ
command detail docker -f フィルタ docker -q ID抽出 xargs <commnad> <command> [パイプされた引数1] [引数2] [引数3] ... docker rmi <imageID> docker イメージ削除 なので
rmidang
というエイリアスにする。
dockerのconfigにエイリアスはないようなので、bashに追加することにした。gitみたいに用意してほしい。
ちなみにdangling
は宙ぶらりんの意。結果
.bashrc# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions alias la="ls -a" #docker ##remove dangling images alias rmidang="docker images -f dangling=true -q | xargs docker rmi"参考
世の中のエンジニアのalias設定
https://qiita.com/reireias/items/d906ab086c3bc4c22147
aliasと関数で幸せになろう
https://qiita.com/belion_freee/items/528ff57b920d559abf3d
aliasの引数使いたいときは関数を使うbash起動時の設定ファイル実行順序
- 投稿日:2020-06-21T03:12:46+09:00
linux alias 設定
linuxのaliasってどうやって設定すんの?
二種類ある。
- 一時的な設定
- 恒久的な設定一時的な設定
これだとログアウトしたりすると消えてしまう。
shellalias name='value'恒久的な設定
homeディレクトリ配下に
.bashrc
ってファイルが隠れているので追記する。.bashrc# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions ★ここに追記 #例 alias la="ls -a"alias確認方法
現在登録されているエイリアスは
alias
コマンドで確認。[ec2-user@~]$ alias alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' alias l.='ls -d .* --color=auto' alias la='ls -a' alias ll='ls -l --color=auto' alias ls='ls --color=auto'経緯
dockerコマンドにエイリアスを設定したかった
同じイメージ名で
docker-compose build
すると<none>:<none>
という空のdockerのイメージファイルができてしまう。
上書きしてほしいところだが、いちいち消すしかないみたい。
だが、削除するために下記のコマンドを毎回打つのは面倒。shelldocker images -f dangling=true -q | xargs docker rmiコマンドメモ
command detail docker -f フィルタ docker -q ID抽出 xargs <commnad> <command> [パイプされた引数1] [引数2] [引数3] ... docker rmi <imageID> docker イメージ削除 なので
rmidang
というエイリアスにする。
dockerのconfigにエイリアスはないようなので、bashに追加することにした。gitみたいに用意してほしい。
ちなみにdangling
は宙ぶらりんの意。結果
.bashrc# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions alias la="ls -a" #docker ##remove dangling images alias rmidang="docker images -f dangling=true -q | xargs docker rmi"参考
世の中のエンジニアのalias設定
https://qiita.com/reireias/items/d906ab086c3bc4c22147
aliasと関数で幸せになろう
https://qiita.com/belion_freee/items/528ff57b920d559abf3d
aliasの引数使いたいときは関数を使うbash起動時の設定ファイル実行順序
- 投稿日:2020-06-21T03:12:46+09:00
dockerコマンドをlinuxのalias設定に設定する
linuxのalias設定方法
二種類ある。
- 一時的な設定
- 恒久的な設定一時的な設定
これだとログアウトしたりすると消えてしまう。
shellalias name='value'恒久的な設定
homeディレクトリ配下に
.bashrc
というファイルが隠れているので追記する。.bashrc# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions ★ここに追記 #例 alias la="ls -a"alias確認
現在登録されているエイリアスは
alias
コマンドで確認。[ec2-user@~]$ alias alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' alias l.='ls -d .* --color=auto' alias la='ls -a' alias ll='ls -l --color=auto' alias ls='ls --color=auto'追加したいdockerコマンド
同じイメージ名で
docker-compose build
すると<none>:<none>
という空のdockerのイメージファイルができてしまう。
上書きしてほしいところだが、下記のコマンドを打っていちいち消すしかないみたい。shelldocker images -f dangling=true -q | xargs docker rmiコマンドメモ
command detail docker -f フィルタ docker -q ID抽出 xargs <commnad> <command> [パイプされた引数1] [引数2] [引数3] ... docker rmi <imageID> docker イメージ削除 削除するために下記のコマンドを毎回打つのは面倒なので、dockerコマンドにエイリアスを設定したかったが、dockerのconfigにエイリアスはないらしい。
しかたなくbashに追加することにした。gitみたいに用意してほしい。今回は
rmidang
というエイリアスにする。
ちなみにdangling
は宙ぶらりんの意。結果
.bashrc# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions alias la="ls -a" #docker ##remove dangling images alias rmidang="docker images -f dangling=true -q | xargs docker rmi"参考
世の中のエンジニアのalias設定
https://qiita.com/reireias/items/d906ab086c3bc4c22147
aliasと関数で幸せになろう
https://qiita.com/belion_freee/items/528ff57b920d559abf3d
aliasの引数使いたいときは関数を使うbash起動時の設定ファイル実行順序
- 投稿日:2020-06-21T02:24:47+09:00
WSL2 Dockerのイメージ・コンテナの格納先を変更したい (WSL2のvhdxファイルを移動させたい)
Docker Desktop backend WSL2 をインストールすると、docker-desktopとdocker-desktop-dataというふたつのディストリビューションが作成されます。
ディストリビューション 役割 実体(デフォルト) docker-desktop Dockerを動かすためのエンジン %LocalAppData%\Docker\wsl\data\ext4.vhdx docker-desktop-data イメージやコンテナを格納する %LocalAppData%\Docker\wsl\distro\ext4.vhdx とくにdocker-desktop-dataについては、
docker pull
などを繰り返すたびにもりもり大きくなっていくため、%LocalAppData%
に置いておきたくない、ドライブごと変えてしまいたいということが十分ありえます。そこで本記事ではdocker-desktopとdocker-desktop-dataの実体である
ext4.vhdx
を別の場所に移動させる方法については記述します。ここでは例として、docker-desktopのext4.vhdx
をD:\wsl\docker-desktop
に、docker-desktop-dataのext4.vhdx
をD:\wsl\docker-desktop-data
にそれぞれ移動させたいと思います。1. Docker Desktopの停止
タスクトレイのDockerマークを右クリックし、
Quit Docker Desktop
を押下する。2. ディストリビューションのエクスポート
ディストリビューションをtarファイルにエクスポートする。
wsl --export docker-desktop docker-desktop.tar wsl --export docker-desktop-data docker-desktop-data.tar3. ディストリビューションの削除
ここでdocker-desktopとdocker-desktop-dataをいったん削除します。
wsl --unregister docker-desktop wsl --unregister docker-desktop-data4. ディストリビューションのインポート
2.でエクスポートしたtarファイルを入力に、ディストリビューションの再インポートを行います。このとき、
ext4.vhdx
の移動先となるフォルダを必ず指定します。wsl --import docker-desktop D:\wsl\docker-desktop docker-desktop.tar wsl --import docker-desktop-data D:\wsl\docker-desktop-data docker-desktop-data.tar5. Docker Desktopの起動
最後に任意の方法でDocker Desktopを起動させれば完了になります。
環境情報
- Dockerのバージョン:
C:\>docker version Client: Docker Engine - Community Version: 19.03.8 API version: 1.40 Go version: go1.12.17 Git commit: afacb8b Built: Wed Mar 11 01:23:10 2020 OS/Arch: windows/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.8 API version: 1.40 (minimum version 1.12) Go version: go1.12.17 Git commit: afacb8b Built: Wed Mar 11 01:29:16 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
- Windowsのバージョン: