20200621のdockerに関する記事は25件です。

【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
├── work
    

docker-compose.ymlの内容

jupyterLab環境を構築するために、docker-compose.ymlに必要な設定を記述する。

docker-compose.yml
version: "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 にアクセス。

以下のような画面が立ち上がれば成功!

スクリーンショット 2020-06-21 23.24.39.png

補足(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の画面となる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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を追加します。

  1. ヘッダのアイコンをクリックして、アドオン管理ダイアログを開きます
  2. マーケットプレイスをクリックし、目的のアドオンを検索します
  3. チェックして、選択済みインストールをクリックするとインストールされます

スクリーンショット 2020-06-21 10.37.37.png

マーケットプレイスを選択し、フィルタに「OpenAPI」と入力すると絞り込めます。チェックを入れて、選択済みをインストールされます。
スクリーンショット 2020-06-21 10.39.54.png

OpenAPIの定義を読み込む

  1. Importメニューから「Import an OpenAPI definition from the local file system」を選択します
  2. 表示されたダイアログで、ローカルファイルを選択します
  3. サイトツリーにAPIが表示されます

スクリーンショット 2020-06-21 10.49.05.png

スクリーンショット 2020-06-21 10.49.33.png

サイトツリーに読み込まれます。Errorになった場合は、フッタメニューのアウトプットタブを見ると、エラー内容が出力されます。
スクリーンショット 2020-06-21 10.57.49.png

読み込まれた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 openapi  
Usage: 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版で読み込んだ方が、見やすいと思います。アラートが出たときのリクエストの内容やレスポンスの内容も確認できますし、そのままで再リクエストもできます。うまく併用するのがいいと思います。
スクリーンショット 2020-06-21 20.51.42.png

まとめ

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/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

dockerイメージ内にyarnをインストールする

背景

Dockerを利用して作成したRailsアプリ(v5.2.4)を本番環境にデプロイする際、アセットをプリコンパイルしようとしたところ、以下のエラーがでて実行できなかった。

$docker-compose run web bundle exec rake assets:precompile RAILS_ENV=production
Starting 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

参考

https://github.com/yarnpkg/yarn/issues/7329

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 ls

container の起動

イメージからコンテナを作成します。
このときに外部接続の設定と、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)

devicename, 使うイメージは適宜読み替えてください。
次の項で、デバイス情報取得で調べ方を記述します。

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で表示する準備ができました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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-indexes

Acquire::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でも良かったんですけど、そっちも同じような問題にぶつかったのかなぁ。。
気が向いたらまた調べて見るくらいで。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.04allD.png

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

試し順番です

  1. デレクトリー移動

    • cd qitta-example/dockerfiles/no-password-sudoer
  2. dockerコンテナをバックグラウンドで起動

    • docker-compose up -d
  3. 各々の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" checkSudoers.png
  4. (選択)自由に確認したいなら、入りたい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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

環境を汚さず(選ばず)Nuxtプロジェクトを作成しGitHub Pagesで公開するまでの一部始終

事前準備

docker がインストールされていることが前提です。
docker が入ってさえいれば Windows, Mac, Linux いずれでも同じように操作できるはずです。

WindowsにDockerを導入する方法は以下にまとめています。

Windows 10 Home に Docker for Desktop をインストールする手順

また、プログラムの編集にはVisualStudioCodeを使いますのでインストールしておいてください。

VisualStudioCodeのインストール手順(Windows)

GitHubからクローンしたりプッシュしたりするのでGitHubのアカウントを用意し git もインストールしておいてください。

Windows に git をインストールする手順


プロジェクト作成

プロジェクトを作る親フォルダに移動
(Windows の場合は例えば C:\dev を作ってコマンドプロンプトで cd \dev で親フォルダとする dev に移動します。)


node.jsが入ったLinuxを起動するため以下のコマンドを実行します。

windows
docker run --rm -itv %cd%:/app node:alpine sh
mac,linux
docker run --rm -itv $PWD:/app node:alpine sh

docker 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:33

Listening on の行が表示されれば起動完了です。
コンテナ内の3000番ポートで動作しています。


ブラウザでの動作確認

起動した画面をブラウザで確認したいですよね。
でも今の状態だと、ブラウザで http://localhost:3000 にアクセスしても何も表示されません。
image.png

なぜかというと、コンテナ内の 3000 ポートは何も設定しないとローカル(PC)からアクセスできないようになっているからです。

ですので、いったんコンテナを終了して、設定を追加してもう一度コンテナを起動します。
Ctrl+Cを押して開発サーバを終了させて、 exit コマンドでコンテナから抜けます。

/app/first_nuxt # exit

まず、作成したプロジェクトフォルダに移動します。

共通
cd first_nuxt

以下のコマンドで開発サーバを起動します。

windows
docker run --rm -itv %cd%:/app -p 80:3000 -e "HOST=0.0.0.0" -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn dev
max,linux
docker 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 と入れればコンテナ内に起動したページを見ることができます。

image.png


ソース編集と自動更新の設定

これで開発できる状態になりました。
さっそく、表示されたトップページを変更してみます。

first_nuxt フォルダを VisualStudioCode で開きます。
image.png
Windowsならフォルダ右クリックで Code で開くを選択します。
(VisualStudioCodeを起動してからフォルダを開くでもOKです)

image.png
作成されたフォルダやファイルが表示されています。


トップページの編集

pages フォルダ内に index.vue というファイルがあります。
image.png
これがトップページの内容になります。

<template> タグ内が表示内容を構成するHTMLです。(通常のHTMLだけではなくVueの記法が使えるようになっています)

<h1>タグ内にタイトルの文字 first_nuxt があるので、
「はじめてのNuxt」に変えてみましょう。
image.png
(ファイルを編集するとファイル名タブに●がつきます。保存すると消えます。)


変更の反映

WindowsならCtrl+S、MacならCommand+Sでファイルが保存できます。

保存すると、おそらくMacやLinux環境ならすぐにブラウザの内容が自動更新され文字が変わります。
image.png

Windows環境やうまく自動更新されない場合は、次の設定をしてみてください。


(Windowsで)自動更新が効かない場合の設定

nuxt.config.js ファイルを開き、末尾に以下の記述を追加して保存します。

変更前
  build: {
  }
}
変更後
  build: {
  },
  watchers: {
    webpack: {
        poll: true
    }
  }
}

そしていったん docker コンテナから抜けて(CTRL+C)以下のコマンドで再度開発環境を起動します。

windows
docker run --rm -itv %cd%:/app -p 80:3000 -e "HOST=0.0.0.0" -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn dev
max,linux
docker 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

これでソースを変更して保存するとすぐにブラウザの表示内容が切り替わるようになります。
image.png

試しに、タイトルを「Nuxtはじめました」に変えてみましょう。
image.png

保存してブラウザを見るとすぐに内容が変わります。
image.png


拡張機能を入れる

vueファイルを見やすくしたり、ミスを教えてくれたりする拡張機能を入れておきます。

画面左の上から6番目のボタンimage.pngを押します。

検索欄に vetur と入れて Vetur という拡張機能を探します。
見つけたら install ボタンを押しまてインストールします。

image.png

インストールできると以下のようにに内容が色分けして表示されます(シンタックスハイライトといいます)
image.png


余分なポートの通信を止める

ブラウザでF12を押し開発者ツールを出します。
そうすると、以下のようにエラーが出ているのが確認できると思います。
image.png
エラーを見ると localhost の 40791 ポートにアクセスしようとしてエラーになっています。
(このポート番号はプロジェクトごとにランダムで変わります。)
このポートも -p 80:3000 としたように Docker 内のポートにつなげないと通信できません。

これは、Nuxtの自動ロード時に進捗率を表示するために使われているようです。
https://ja.nuxtjs.org/api/configuration-build/#indicator
image.png
エラーは出てほしくないのでこの設定をOFFにします。

nuxt.config.js ファイルを開き、以下のように変更して保存します。

変更前
  build: {
  },
変更後
  build: {
    indicator: false
  },

もしくは、ONのままにしたい場合は、docker run 実行時に -p 40791:40791 のようにポートの通信を通すようにします。


github pages に公開する

まだトップページしかありませんが、動作はするので、これを Github pages にデプロイしてみましょう。

静的ファイルの生成

docker コンテナを一度終了して、以下のコマンドを実行します。

windows
docker run --rm -itv %cd%:/app -e "NUXT_TELEMETRY_DISABLED=1" -w /app node:alpine yarn generate
max,linux
docker 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.

dist というフォルダに静的ファイルが生成されました。
image.png

これらのファイルをレンタルサーバ等に置けばインターネット上に公開できます。

今回はこのファイルを GitHub Pages で公開します。
GitHub には GitHub Actions というコマンド実行機能がありますので、それを使って、push 時今の生成操作を自動実行して公開できるように設定していきます。


GitHub Actions 用ファイルの作成

FIRST_NUXT フォルダ直下に .github/workflows フォルダを作成します。

具体的には、nuxt.config.jsなど直下のファイルを選択した状態で
フォルダ作成ボタンimage.pngを押します。

出てきたフォルダ名入力欄に .github/workflows を入力します。(先頭のピリオドを忘れないでください)
image.png

フォルダが作成されます。
image.png


作成したworkflowフォルダを選択した状態で、ファイル作成ボタンimage.pngを押して、gh-pages.yml ファイルを作成します。

image.png

ファイルの内容は以下の通り入力し、保存します。
image.png

.github/workflows/gh-pages.yml
name: 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のアカウント作成からプッシュするまでをまとめていますので参考にして、
リポジトリ作成まで(「ローカルにクローンする」の手前まで)進めてください。

GitHubのアカウントを作成して、リポジトリ作成、クローン、コミット、プッシュまでの手順


ローカルのGit管理開始

ローカルで Git の初期化を行います。

first_nuxt フォルダ上で git init コマンドを実行します。

git初期化
git init

image.png

初期化したあと、VisualStudioCodeのソース管理image.pngを見ると、
gitでまだコミットされていないファイルが列挙されてきます。
image.png


GitHubリポジトリをリモートリポジトリとしてセット

ローカルのgitリポジトリとGitHubのリポジトリを関連付けます。

リモートリポジトリ設定
git remote add origin https://github.com/GitHubアカウント名/リポジトリ名.git

※GitHubアカウント名、リポジトリ名はご自身で作成したものを指定します。

登録されたかどうかは git remote -v で確認できます。
image.png


コミットする

VisualStudioCodeでソース管理の上部分にコミットコメントを入力します。
今回は「初コミット」としています。
image.png

コミットボタンimage.pngを押します。

ステージされていないファイルをコミットするかの確認が出ます。全ファイルコミットするので Yes を押します。
image.png

以下の画面が出る場合はCancelボタンを押して、git config コマンドで名前とメールアドレスを設定してから再度コミットしてください。
image.png

名前、メールアドレス設定
git config user.name あなたの名前
git config user.email GitHubに登録したメールアドレス

コミットされると、コメント欄、一覧が空になります。
image.png


GitHub に push

その他ボタンimage.pngを押し、Push to...を選択します。
image.png

origin を選択します。
image.png

2回目以降はPush先が記録されるので Push to ではなく Push で実行可能です。


GitHubにログインしていない場合は以下の画面が出ます。ログインします。
image.png


上向きの矢印が出ない状態になっていればPushされています。

●Pushされている状態
image.png

●Pushされていない状態
image.png


動作確認

Pushすると GitHub Actions が実行され GitHub Pages にページが公開されているはずです。

公開先URLは以下の通りです。
https://GitHubのユーザ名.github.io/プロジェクト名(今回はfirst_nuxt)/

例えば私が作ったURLは
https://github-japanese-user.github.io/first_nuxt/
になります。
image.png

もし、404エラーが表示される場合は正しくHTMLが登録されている確認します。
image.png


GitHub Pages に公開されているかを確認する

GitHubのリポジトリページに行き、Branchボタンを押して、gh-pages を選択します。
gh-pages というのが生成されたHTMLが格納されているブランチになります。

image.png

gh-pages のファイル内に index.html があれば生成は成功しています。

image.png


次に、設定を確認します。

同じ画面の右上にある Settings ボタンimage.pngを押します。
image.png

設定画面の下を見ていくと、GitHub Pages の設定部分があります。
image.png

ここの 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エラーになっているファイルが見つかります。
image.png

これは、通常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 を選択すると確認できます。
image.png
変更前と後の内容が左右に並び、変更した行がマークされています。
これをみて間違いがないかを確認できたら、コミットコメント
image.png
を入力して、コミットボタンimage.pngを押します。


つづけて、その他ボタンから Push を実行します。
image.png


Push すると GitHub Action が動作しますので、GitHubのリポジトリページから Actions タブを開いて
動作が完了しているか確認してみましょう。

image.png
コミットコメントの左が黄色マークの場合はまだ実行中です。

image.png
緑のチェックマークになれば実行完了です。


ブラウザでトップページをリロードして404エラーが消えていることを確認します。
image.png


長くなりましたが、以上ですべての作業が完了しました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

よく使うDockerコマンドまとめ

この記事について

この記事は、

  • 開発時に私個人がよく使うdockerコマンド
  • 開発時に気になったdockerコマンドの細かい挙動
  • コンテナを支えるネットワーク・ボリュームといった裏の仕組み

だけに絞って書き残したものです。
「よく使うコマンドだけ手っ取り早く知りたい」「コンテナという概念は知っている状態から、もっとdockerシステムについての理解を深めたい」という人には役立つかもしれません。

注:「コンテナについての一からの解説が欲しい」「dockerコマンドにはどういう機能があるのかを網羅的に知りたい」という方のニーズは満たせていません。

使用する環境・バージョン

  • Mac OS Mojave 10.14.5
  • Docker version 19.03.8

Containers

コンテナの新規作成・起動

docker runは指定したイメージから新しくコンテナを作成・起動するコマンドです。

ただし、コンテナの元になるイメージ(DockerfileFROM命令で指定されたもの)がローカルにまだインストールされていない場合、DockerデーモンがそのコンテナイメージをDocker Hub(Docker社が運営するPaaS型のDocker Registry)から自動でダウンロードし、イメージからコンテナを起動します。
この挙動から、docker runは「docker pulldocker createdocker 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 : コンテナ起動時にコンテナ中で実行されたコマンド(DockerfileCMD命令にあたる)
  • 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-03-03-1536x1024.png
上図引用:Docker Compose入門 (3) ~ネットワークの理解を深める~

none

このネットワークを使うように指定されたコンテナには、外部のネットワークに繋ぐインターフェースが一切設置されません。
もちろんコンテナホストのPCと繋がるインターフェースも設置されないので、用途としてはネットワーク接続を必要としない開発環境を用意するときでしょう。

host

この設定では、コンテナとホストがネットワークインターフェースを共有するものです。なので、コンテナのeth0とホストのeth0がそのまま繋がります。
これを利用すると、コンテナがホストマシンと同じIPアドレスを持つようになります。

bridge

この設定では、ホストの任意のポートをコンテナのポートにマップすることで、コンテナ外部のネットワークに接続します。
例えば、先ほど紹介したdocker run -p 80:3000というコマンドは、bridgeで「コンテナの3000番ポートをホストの80番ポートに繋ぐ」という設定をしていることになります。

コンテナーホスト間のポートマッピングは、ホストマシンのLinuxカーネル内部に作られるイーサネット・ブリッジによって行われています(この仮想ブリッジにはdocker0という名前がついています)。
l_docker29-001.jpg
上図引用:第29回 Docker Networkingの基礎知識 標準的なネットワークを理解する (4/5)

コンテナ内部とdocker0仮想ブリッジは、veth(Virtual Ethernet Tunnel)によって接続されています。vethペアのうち、コンテナ側のインターフェースは、コンテナ内ではeth0として振る舞います。残ったホスト側の方は、docker0ブリッジにつながるインターフェースとなります。
docker0ブリッジには、ホストマシンのeth0にも繋がっています。

そのため、コンテナから外部への通信は、docker0ブリッジを経由し、そこでブリッジが提供するNAT機能を用いることで行うことになります。

ただし、このbridgeネットワークには名前解決機能がありません。
例えば、bridgeネットワークに同時にcontainer1container2というコンテナ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-03-02.png
上図引用: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
# 以下削除処理
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

データサイエンス100本ノック(構造化データ加工編)の環境構築(Windows10)

はじめに

一般社団法人データサイエンティスト協会が、構造化データの加工を実践的に学べる無料の学習環境「データサイエンス100本ノック(構造化データ加工編)」GitHubに公開しました。
本記事は、初学者の方でも無料の学習環境を構築できるように、導入手順の詳細を記載しました。
(構築する実行環境は下図になります。)
dss_structure.png

前提条件(Windows10)

  1. Docker Desktop for Windows
    ※起動しない場合は、Hyper-Vが「無効」になっている可能性があるので「有効」に設定。
  2. 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ファイルがある。
必要ライブラリのインポートや加工前のデータ取得は、最初のセルに記述済み。
演習問題に適した処理を、空欄のセルに入力して実行し、学習を進める。
dss_jupyter_work.png
演習問題の解答は、work/answerディレクトリ内に.ipynbファイルがある。
そのため、演習問題のファイルで回答した処理の正否を確認しながら作業可能。
dss_jupyter_answer.png

学習環境の停止・起動

下記のコマンドで、構築した環境を停止可能。

> docker-compose stop

また、2回目以降に起動する場合は、下記のコマンドで起動可能。

> docker-compose start

補足事項

構築した環境のレスポンスが遅い場合

Docker Desktop for WindowsのSettingsでResourcesでMemoryの値を変更してください。
推奨は、4.00GB以上です。
docker_settings_resources.png

8888ポートが使用されている場合

もし、ローカルホストの8888ポートを他の開発環境(LAMPなど)で利用している場合は、docker-compose.ymlを下記のように変更(notebookのportsの値を変更)することで対応可能。

docker-compose.yml
  notebook:
    ports:
      - "888:8888"

上記の場合、下記のURLでアクセス可能になる。

http://localhost:888

まとめ

Windows10環境における、データサイエンス100本ノック(構造化データ加工編)の環境構築手順を記載いたしました。
上記の手順で不明点や疑問点等がありましたら、コメントいただけますと幸いです。

参考リンク

データサイエンス100本ノックのガイド

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ECSにdockerfileをpushしたときのメモ

AWS ECSリポジトリの作成後「プッシュコマンドの表示」をクリックすると下記が表示される。
pushのための実行コマンドが表示され、macOS/Linux もしくは Windowsと環境に合わせて選ぶように表示される。

Amazon ECR.png

注意点

私はWindows環境だが、この表示される「Windows」とはホストOSを指すのではなく、使用するターミナルのことで、AWS Tools for Windows PowerShell を使用する場合という意味と思われる。
Windows環境下でもAWS Command Line Interface(AWS CTL)を使用している場合はmacOS/Linuxに表示されるコマンドを実行すること。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ECRにdockerfileをpushしたときのメモ

AWS ECRリポジトリの作成後「プッシュコマンドの表示」をクリックすると下記が表示される。
pushのための実行コマンドが表示され、macOS/Linux もしくは Windowsと環境に合わせて選ぶように表示される。

Amazon ECR.png

注意点

私はWindows環境だが、この表示される「Windows」とはホストOSを指すのではなく、使用するターミナルのことで、AWS Tools for Windows PowerShell を使用する場合という意味と思われる。
Windows環境下でもAWS Command Line Interface(AWS CTL)を使用している場合はmacOS/Linuxに表示されるコマンドを実行すること。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

基本的な流れ

  1. コンテナをpullしてくる。
  2. コンテナを起動してコンテナ内のbash環境に入る。
  3. コンテナ内のjupyter認証用ハッシュを生成。
  4. 一旦コンテナから出る。
  5. 生成したハッシュを使用してコンテナ&jupyter起動。
  6. ブラウザ等でlocalhostに入る。
  7. ハッシュを入力。jupyterのトップ画面に入れたら成功。

コマンド

1.コンテナをpullしてくる。

sudo docker pull jupyter/datascience-notebook

datascience-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:8888

7.ハッシュを入力。jupyterのトップ画面に入れたら成功。

dockerの終了は

sudo docker stop コンテナID

docker終了後、再度コンテナを開くとき

sudo docker start コンテナID

のあと、いつもどおりlocalhost:8888へアクセスすればOK。

メモ

jupyterのportは通常は8888となっていると思われるがローカル環境でjupyterを起動するなど8888のportが使用済みだったりするとdockerのjupyterを起動できない。
portを設定しないでjupyterを起動する場合、自動で使用していないportを使ったりしてくれるけどfirewallでそのportが開放されてないなどの状況もあるので、
portの使用状況は確認してから使う。

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

基本的な流れ

  1. コンテナをpullしてくる。
  2. コンテナを起動してコンテナ内のbash環境に入る。
  3. コンテナ内のjupyter認証用ハッシュを生成。
  4. 一旦コンテナから出る。
  5. 生成したハッシュを使用してコンテナ&jupyter起動。
  6. ブラウザ等でlocalhostに入る。
  7. ハッシュを入力。jupyterのトップ画面に入れたら成功。

コマンド

1.コンテナをpullしてくる。

sudo docker pull jupyter/datascience-notebook

datascience-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:8888

7.ハッシュを入力。jupyterのトップ画面に入れたら成功。

dockerの終了は

sudo docker stop コンテナID

docker終了後、再度コンテナを開くとき

sudo docker start コンテナID

のあと、いつもどおりlocalhost:8888へアクセスすればOK。

メモ

jupyterのportは通常は8888となっていると思われるがローカル環境でjupyterを起動するなど8888のportが使用済みだったりするとdockerのjupyterを起動できない。
portを設定しないでjupyterを起動する場合、自動で使用していないportを使ったりしてくれるけどfirewallでそのportが開放されてないなどの状況もあるので、
portの使用状況は確認してから使う。

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 p11

MySQL

  • 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 m8

SQLite

  • 公式dockerイメージは見つからなかった。
  • 出力をカンマ区切りにするためには $'\t', に変更すればよい
docker run -it --rm nouchka/sqlite3 sqlite3 -header -separator $'\t'
sqlite> .q
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 Dockerfile

Ansibleを動かすためpython3を使用します。
WORKDIRは後ほど作成するAnsibleのファイルを置くディレクトリを指定します。
今回はsshのパスワード認証でUbuntuサーバに接続するため、sshとsshpassをインストールします。

Dockerfile
FROM python:3

WORKDIR /usr/src/app

RUN pip install ansible==2.9
RUN apt-get update && apt-get install -y \
ssh \
sshpass

Dockerfileからイメージを構築
イメージ名を「test-ansible」としています。

$ docker build -t test-ansible .

Ansible環境作成

Ansibleのファイルを保存するディレクトリ作成

$ sudo mkdir -p /usr/src/app
$ cd /usr/src/app

inventoryファイルと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@ssW0rd
playbook.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.txt
test.txt
test 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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker+JupyterLabで決定木モデルの可視化(graphviz/dtreeviz)

概要

決定木についての詳細は記載しませんが、決定木によって生成されたモデルの可視化で一般的なのがgraphvizです。これをDocker+JuptyerLabの環境で使おうとしたら微妙にハマった部分があったので、やり方をまとめておきます。またgraphvizではなく、より分かり易い可視化でdtreevizが便利だったのでそちらも記載します。

環境

以下を参考にDockerでJupyterLabが使える状態を前提とします。
Dockerで起動したJupyterLabでvimキーバインドを使う

Dockerfile

Dockerfileに以下追記してビルドし直す事でgraphvizとdtreevizが使えるようになりました。

Dockerfile
RUN 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 graphviz

graphvizはPythonのライブラリとLinuxのライブラリで両方入れる必要があり、
Linuxライブラリの方がなかなかうまく入ってくれなかったですが、上記でうまくできました。

Dockerfileの全体についてはこちらにもまとめてあります。
https://github.com/hikarut/Data-Science/blob/master/Dockerfile

モデルの可視化

graphviz

スクリーンショット 2020-06-21 10.34.59.png

  • 1行目:条件式
  • 2行目:ジニ係数
  • 3行目:ノードのサンプル数(サンプル割合)
  • 4行目:クラス毎のサンプル数(サンプル割合)

dtreeviz

スクリーンショット 2020-06-21 10.35.13.png

向きを左→右にする事もできます。
スクリーンショット 2020-06-21 11.02.13.png

ソース
https://github.com/hikarut/Data-Science/blob/master/notebooks/decisionTree/sample.ipynb

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerコンテナのホストでGUIを起動する

環境

Ubuntu20.04
Docker 19.03

1.ホストでの準備

下記のコマンドで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/bash

参照

3.GUIが使えるかの確認

コンテナのbash上で下記のコマンドを実行してGUIが使えるかを確認

1.xeyesを使う

apt update
apt install x11-apps
xeyes

2.matplotlibを使う

test.py
import matplotlib.pyplot as plt
img=list([[2,3,4],[5,6,7]])
plt.imshow(img, cmap='Greys')
plt.show() #画像を表示させる

上記のコードをpythonで実行
参照

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.md

services:
  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

参考サイト

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerファイルがビルドできなかったのでコンパイラをいじめる

TL;DR

  • ある環境でビルドできたDockerfileが別の環境でビルドできなかったのは、メモリ制限のせいだった

はじめに

理研シミュレータというシミュレータがあります。

RIKEN-RCCS/riken_simulator

これは、「京」の次のスーパーコンピュータ「富岳」が採用しているアーキテクチャ「Fujitsu A64FX」のシミュレータです。Gem5というアーキテクチャシミュレータがあり、それにARM AArch64を実装したものです。

これを使うと、AArch64のプロセッサレベルでのシミュレートができるのですが、ビルドに結構手間がかかります。なので、その「手間」をまとめたDockerファイルを作りました。

kaityo256/aarch64env

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のままビルドします。こけます。
j20.png

internal compiler errorさんお久しぶりです。整数を419378回インクリメントした時以来ですね。internal compiler error、略してICEですが、普通に生きていればあまり見かけないと思います。・・・というようなことをあるところで口走ったら、「え?ICEなんて日常的に見ますよね?」みたいな反応があったのでC++ガチ勢は怖いなと思いました。閑話休題。

とりあえず4コアしかないマシンで20並列するのもアレなんで、-j 4でやり直してみます。

j4.png

やっぱりこけますね。

さて、ビルドに失敗する理由がICEである、ということから、メモリ不足を疑います。

まず、LinuxサーバでDockerfileをビルド中にdocker statsで利用メモリを確認します。

memory.png

おおぅ、2.9GB使ってますね。

次に、ローカルのDockerのメモリ制限を見てみましょう。

docker_memory.png

Memoryが2.00GB。これですね。

メモリが潤沢にあるLinuxマシンで、2GBのメモリ制限をかけてビルドしなおしてみましょう。

docker build -t kaityo256/aarch64env:memtest -m 2gb . --no-cache 

linux_failed.png

はい、こけましたね。メモリ不足が原因と確定です。ローカルマシンでビルドに失敗した人には、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

あるところでメモリを使い切り、ビルドが進まなくなります。

memory_full.png

ここでビルドを止めます。どこで止まったか調べるため、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で監視すると、メモリを使い切っていることがわかります。

memory_full_single.png

メモリが十分にあればビルドできるはずなので、このファイルをビルドするのにどれくらいのメモリが必要なのか調べてみましょう。

一度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.ccinst-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: 0

2GBくらい使っています。元のビルドオプションには-gもついていたため、さらにメモリを食っていましたが、外しても結構あります。行数を見てみましょうか。

$ wc expanded.cc
 203875  533178 5907751 expanded.cc

20万行ですか。なかなかですね。

とりあえず、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: 0

627MBですか。もう一声って感じですかね。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ファイルがビルドできない、という連絡を受け、その原因がメモリ不足であること、その原因となるファイルの特定とかやっているうちに、いつのまにかコンパイラをいじめていました。なぜだ?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

linux alias 設定メモ./bashrc

linuxのaliasってどうやって設定すんの?

二種類ある。
- 一時的な設定
- 恒久的な設定

一時的な設定

これだとログアウトしたりすると消えてしまう。

shell
alias 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のイメージファイルができてしまう。
上書きしてほしいところだが、いちいち消すしかないみたい。
だが、削除するために下記のコマンドを毎回打つのは面倒。

shell
docker 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起動時の設定ファイル実行順序

https://qiita.com/tatesuke/items/88629e9550b813109964

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

linux alias 設定メモ

linuxのaliasってどうやって設定すんの?

二種類ある。
- 一時的な設定
- 恒久的な設定

一時的な設定

これだとログアウトしたりすると消えてしまう。

shell
alias 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のイメージファイルができてしまう。
上書きしてほしいところだが、いちいち消すしかないみたい。
だが、削除するために下記のコマンドを毎回打つのは面倒。

shell
docker 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起動時の設定ファイル実行順序

https://qiita.com/tatesuke/items/88629e9550b813109964

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

linux alias 設定

linuxのaliasってどうやって設定すんの?

二種類ある。
- 一時的な設定
- 恒久的な設定

一時的な設定

これだとログアウトしたりすると消えてしまう。

shell
alias 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のイメージファイルができてしまう。
上書きしてほしいところだが、いちいち消すしかないみたい。
だが、削除するために下記のコマンドを毎回打つのは面倒。

shell
docker 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起動時の設定ファイル実行順序

https://qiita.com/tatesuke/items/88629e9550b813109964

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

dockerコマンドをlinuxのalias設定に設定する

linuxのalias設定方法

二種類ある。
- 一時的な設定
- 恒久的な設定

一時的な設定

これだとログアウトしたりすると消えてしまう。

shell
alias 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のイメージファイルができてしまう。
上書きしてほしいところだが、下記のコマンドを打っていちいち消すしかないみたい。

shell
docker 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起動時の設定ファイル実行順序

https://qiita.com/tatesuke/items/88629e9550b813109964

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.vhdxD:\wsl\docker-desktopに、docker-desktop-dataのext4.vhdxD:\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.tar

3. ディストリビューションの削除

ここでdocker-desktopとdocker-desktop-dataをいったん削除します。

wsl --unregister docker-desktop
wsl --unregister docker-desktop-data 

4. ディストリビューションのインポート

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.tar

5. 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のバージョン:

image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む