- 投稿日:2019-12-09T23:48:00+09:00
Windows 10 HomeのWSL2でdocker-composeを使う
この記事はニフティグループ Advent Calendar 2019の10日目の記事です。
入社1年目研修の一環としてLaravelフレームワークを使ってのチーム開発を行いました。
せっかくならば家でもLaravelで開発を行おうと思い、研修時にも使ったLaradockを用いて環境構築を行おうと考えました。ところがちょっと待てよ、自分のPCはWindowsじゃないか。
Dockerを動かすのがかなり面倒だと聞いたぞ。
VM立てたりしなきゃいけないのか…?やる気を削がれつつ調べてみると、WSL2を用いてDocker(docker-compose)が使えるようだったので、そちらを採用して環境構築を進めていきました。
環境
- Windows 10 Home
- バージョン 1903
- OSビルド 18362.418
WSL2の導入
WSL2は2019/12/08現在は正式リリースされておらず、2020年の春に正式リリースされるのではと噂されていたりします。
現段階でWSL2を使うためには、OSビルドの先行リリースをプレビューできるWindows Insider Programに登録し、β版として使う必要があります。Windows Insider Programの利用を開始する
WSL2を使うための要件を一読し、公式サイトにしたがってWindows Insider Programの利用を開始します。
要約すると以下のような感じです。
- Microsoftの公式ページから自身のMicrosoftアカウントをInsiderとして登録。
- 管理者権限のあるユーザーで、
スタート
>設定
>更新とセキュリティ
>Windows Insider Program
から開始する
をクリック。アカウントを選んで開始
からWindows Insider Programに登録したMicrosoftアカウントを入力。- 受信したいコンテンツの種類と受信頻度を適切に選択し、PCを再起動。
WSL2を使うための要件では受信頻度を"ファスト"にせよという指示がありますが、11/17時点では"スロー"でも必要なビルドを受信することができました。
"ファスト"はややリスクが大きいですので、"スロー"を選択することを推奨します。また、私の環境の場合、ビルドの受信とインストールには数時間かかりました。
マシンスペックとネットワークの状況によりけりかとは思いますが、時間の余裕のある時に行いましょう。
スタート
>設定
>システム
>バージョン情報
にあるWindowsの仕様
の項目から、インストール済みのビルドを確認できます。ビルドが18917以降になっていれば準備完了です。
WLS1を有効化する
WSL2はWSL1をアップグレードすることで使えるようになります。
なので、あらかじめWSL1を使える状態にしておきます。
スタート
>設定
>アプリ
>アプリと機能
の関連項目
からプログラムと機能
をクリック。- 左の一覧から
Windowsの機能の有効化または無効化
をクリック。- 以下の3つを有効化して再起動します。
- Linux用Windowsサブシステム
- Windowsハイパーバイザー プラットフォーム
- 仮想マシンプラットフォーム
Microsoft Store
を開き、検索窓でUbuntu 18.04 LTS
と検索し、入手
をクリック。インストールを完了します。- スタートメニューからUbuntuを起動し、ユーザー名とパスワードを設定します。
Installing, this may take a few minutes... Installation successful! Please create a default UNIX user account. The username does not need to match your Windows username. For more information visit: https://aka.ms/wslusers Enter new UNIX username: ←ユーザー名を入力 Enter new UNIX password: ←パスワードを入力
WSL2へアップグレード
公式サイトの手順に従いWSL2を導入します。
コンポーネントの有効化はGUIからすでに行ったのでスキップします。PowerShellを管理者権限で実行し、以下のコマンドを叩きます。
wsl --set-version Ubuntu-18.04 2バージョン確認を行い、
VERSION
が2となっていればWSL2の導入は完了です。wsl -l -vDockerの導入
WLS2で動くようになったLinux環境にDockerを導入していきます。
基本的にはDockerの公式の案内に従います。Dockerをインストールする
公式サイトで案内されているインストール方法のうち、今回は簡単そうな"Install using the convenience script"を試してみます。
正式なプロダクトへの使用は推奨されていないらしいので自己責任でお願いいたします。WindowsのスタートメニューからUbuntuを開き、以下のコマンドを叩きます。
$ curl -fsSL https://get.docker.com -o get-docker.sh $ sudo sh get-docker.sh $ sudo usermod -aG docker your-userこれだけで完了です。
念のためバージョンをチェックします。$ docker -vdocker-composeをインストールする
[公式サイト]のLinux用の案内に従い、以下のコマンドを叩きます。
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose $ sudo chmod +x /usr/local/bin/docker-compose以上です。
バージョンチェックもしてみます。$ docker-compose --versionWSL1ではここまで完了したとしても、いざdocker-composeでコンテナを起動しようとするとコケてしまうようでした。
それはWSL1はネットワークまわりが不完全だったかららしいですが、WSL2ではそれが改善されているようです。おまけ:Laravel環境の導入
せっかくなのでdocker-composeでLaraDockを立ち上げてみます。
こちらはメイントピックから外れるので詳細は記しません。
以下の記事を参考にインストールを行いました。デーモンとコンテナを起動すると、無事にlocalhostからウェルカムページを見ることができました。
docker-composeもlocalhostもきちんと生きていますね!$ sudo /etc/init.d/docker start $ docker-compose up -d workspace nginx mysqlまとめ
VMを立てることなくWindows 10 HomeのWSL2でLinuxを動かしdocker-composeを使うことができました。
WSL2を使うにはWindows Insider Programへの参加が必要でしたが、今回用いた
WSL2
以外にもWindows 10 Pro + Hyper-V
やDocker for Windows
でDockerを動かすことができるようなので、要件に合わせて使い分けたいですね。参考
- Windows10 HomeでLinuxに寄せた開発環境を整える
- Windows 10でLinuxを使う!正式機能になったWSLの導入方法
- Windows10にWSLで作った環境にdockerをインストールするまで
- WSLで「普通」にDockerが動くようになっていた話(しかしdocker-composeは動かない)
- Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能
明日は@iNakamuraくんが自然言語処理について書いてくれるようです。お楽しみに!
- 投稿日:2019-12-09T21:32:10+09:00
アプリケーションのHTTPプロキシのテスト環境を作る
やりたいこと〜
ツール類やデスクトップアプリケーションを作る際に HTTP プロキシ対応をしたりしますが、テストする際に環境がなくて困ったりします。
この記事では docker-compose を使って、テスト用の HTTP プロキシ環境をいつでも再現できるようにします。
UNIX 系 OS ベースの話になります。
NTLM はしません。コード
本記事のすぐ動くコードは ↓ にあります。
単に HTTP プロキシを立てる
以下のコードを書きます。
docker-compose.yml
Dockerfile
squid.conf.template
(envsubst 用のテンプレートファイル).env
(環境変数 = 変更可能なパラメータ)まず
.env
ファイルで Squid HTTP Proxy の待受ポートと、BASIC 認証の有無を、環境変数として指定できるようにします。# 待受ポート HTTP_PORT=3128 # BASIC 認証の設定 (default ではコメントアウト → "#" で OFF) BASIC_AUTH_COMMENT_OUT=# BASIC_AUTH_USERNAME=squid BASIC_AUTH_PASSWORD=passwordオーケストレーションファイル
docker-compose.yml
でコンテナの起動方法を定義します。version: '3.1' services: squid: build: ./squid expose: - "${HTTP_PORT}" ports: - "${HTTP_PORT}:${HTTP_PORT}" environment: - HTTP_PORT - BASIC_AUTH_COMMENT_OUT - BASIC_AUTH_USERNAME - BASIC_AUTH_PASSWORDコンテナイメージ定義
Dockerfile
で Squid HTTP Proxy の構築をします。FROM alpine:3.10 # Set correct environment variables. ENV HOME /root ENV LANG en_US.UTF-8 ENV LC_ALL en_US.UTF-8 # install PKGs. RUN apk update && \ apk --no-cache add squid libintl apache2-utils && \ apk --no-cache add --virtual .gettext gettext && \ cp /usr/bin/envsubst /usr/local/bin/envsubst && \ apk del .gettext # edit squid settings. COPY squid.conf.template /etc/squid/squid.conf.template # user. RUN chown -R squid:squid /etc/squid/ /var/run/ USER squid # entrypoint. ENTRYPOINT /bin/sh -c " \ /bin/touch /etc/squid/passwd && \ /usr/bin/htpasswd -b /etc/squid/passwd ${BASIC_AUTH_USERNAME} ${BASIC_AUTH_PASSWORD} && \ /usr/local/bin/envsubst < /etc/squid/squid.conf.template > /etc/squid/squid.conf && \ /usr/sbin/squid -N -d 1 -f /etc/squid/squid.conf "最後に
squid.conf.template
です。 長いので 設定ファイルのリンク だけ。
標準のsquid.conf
に、以下の設定とenvsubst
用の変数を埋め込んでいます。
- BASIC 認証 の設定を追加しました
- 待受ポート は環境変数で変更できるようにしました
- キャッシュは OFF にしました
- ログは stdout に出す 様にしました (コンテナ化の流儀)
あとはビルドして起動します。
docker-compose build docker-compose up -d
待受ポートをホストにフォワードしているので、ローカルアクセスできます。
[面倒] HTTP プロキシを経由しないとインターネットに出れない環境を作る
実際にテストする際に、Default Gateway からインターネットに出れちゃう環境だと、ちゃんとプロキシ経由してるか (漏れてて直接インターネットアクセスしてるのあるかも) 保証できないので、そういう環境を作りたいと思います。
作業用の OS イメージは、比較的ユーザーが多いであろう
ubuntu:18.04
でいきます。先程の
docker-compose.yml
を修正します。version: '3.1' services: # ↓ここを足しました。 app: image: ubuntu:18.04 entrypoint: - tail - -f - /dev/null privileged: true squid: build: ./squid expose: - "${HTTP_PORT}" ports: - "${HTTP_PORT}:${HTTP_PORT}" environment: - HTTP_PORT - BASIC_AUTH_COMMENT_OUT - BASIC_AUTH_USERNAME - BASIC_AUTH_PASSWORDコンテナ起動しなおします。
docker-compose down docker-compose up -d
コンテナ
app
に入ります。docker exec -it squid-for-http-proxy-testing_app_1 bashネットワークをいじる為に必要なコマンドを入れます。
apt update apt install -y net-tools iputils-ping curlアプリケーションを動作させる為に必要な物があれば、このタイミングで一緒にインストールしておきます。
この時点ではインターネットにアクセスできます。
curl google.com <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>301 Moved</TITLE></HEAD><BODY> <H1>301 Moved</H1> The document has moved <A HREF="http://www.google.com/">here</A>. </BODY></HTML>ルーティングテーブルを見てみます。
① Default Gateway と ② Docker ネットワーク (他のコンテナ) へのルーティングがあります。route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default 172.23.0.1 0.0.0.0 UG 0 0 0 eth0 172.23.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0① Default Gateway のルーティングを消します。 (かなり荒っぽい方法ですが...)
route delete defaultroute Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 172.23.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0インターネットにアクセスできなくなりました。
curl google.com curl: (6) Could not resolve host: google.comプロキシ設定をします。
export http_proxy=http://squid:3128 export https_proxy=${http_proxy}
- ホスト名
squid
は、Squid Proxy コンテナの IP172.xx.xx.xx
を指してします。- 当然ですが、上記の設定は、この bash プロセス上だけで有効です。
HTTP プロキシを経由してインターネットに出れました。
curl google.com <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>301 Moved</TITLE></HEAD><BODY> <H1>301 Moved</H1> The document has moved <A HREF="http://www.google.com/">here</A>. </BODY></HTML>あとは
docker cp {ローカルファイル} {コンテナ名}:/root/
等を使って、この環境にアプリケーションを送信し、アプリケーションの動作・テストします。
- 投稿日:2019-12-09T21:30:54+09:00
Dockerでnginx-proxyを使ったhttps(http2)リバースプロキシで開発環境を便利にする
Docker で nginx-proxy を使った https(http2) リバースプロキシで開発環境を便利にする
前置き
諸先輩方のお知恵を拝借して、楽に開発環境を構築できる時代になりました。良い時代だなぁ〜
とはいえ、自分のやりたい事にジャストな情報というのは意外とないもので・・・
Mac / Win どちらでもとなると希少価値はグンと跳ね上がります!
そこで、個人的なローカル環境をいい感じに構築してみた内容をご紹介します。
内容
- nginxを使ったリバースプロキシ on Docker - Qiita
- ローカル環境用SSLサーバ証明書を簡単に発行する(mkcert) - Qiita
- Docker の nginx オフィシャルイメージで http2 を有効にするには - Qiita
- PlantUML Server を Docker で動かすときの URL ルート設定
- docker-compose.ymlでDockerfileを指定したい - Qiita
(順不同)を参考に
のローカル環境を Docker で構築してみました。
ポイント
- 極力楽に
- 極力最新に
- 極力環境依存ナシに
- 極力汎用的(自由度高)に
苦労した点
- Win (Windows10 WSL1) と Mac では工夫しないと共通化出来ない
docker-compose
でわざわざDockerfile
を呼んで、ファイルのマウントからCOPY
に変更- SSLサーバ証明書は Let’s Encrypt が公式にも世の中的にも推されているが、ローカル環境では Too Match
mkcert
で楽々証明書発行構成
~/local |--.gitignore |--LICENSE |--README.md |--nginx-proxy | |--Dockerfile | |--certs | | |--.gitkeep | | |--plantuml.docker.crt | | |--plantuml.docker.key | | |--quickchart.docker.crt | | |--quickchart.docker.key | |--docker-compose.yml | |--my_proxy.conf |--plantuml-server | |--Dockerfile | |--docker-compose.yml | |--docker-entrypoint-custom.sh |--quickchart | |--docker-compose.ymlnginx-proxy
docker-compose.ymlversion: '3' services: nginx-proxy: # image: jwilder/nginx-proxy:alpine build: context: . dockerfile: Dockerfile container_name: nginx-proxy restart: always ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro # - ./my_proxy.conf:/etc/nginx/conf.d/my_proxy.conf:ro # - ./certs:/etc/nginx/certs:ro environment: - TZ=Asia/Tokyo networks: default: external: name: nginx-proxyコメントアウトした箇所を Dockerfile へ移動
DockerfileFROM jwilder/nginx-proxy:alpine COPY ./my_proxy.conf /etc/nginx/conf.d/my_proxy.conf COPY ./certs /etc/nginx/certsplantuml-server
docker-compose.ymlversion: '3' services: plantuml-server: # image: plantuml/plantuml-server:jetty build: context: . dockerfile: Dockerfile container_name: plantuml-server restart: always # volumes: # - ./docker-entrypoint-custom.sh:/docker-entrypoint-custom.sh entrypoint: /docker-entrypoint-custom.sh environment: - TZ=Asia/Tokyo - VIRTUAL_HOST=www.plantuml.docker - VIRTUAL_PORT=8080 - CERT_NAME=plantuml.docker networks: default: external: name: nginx-proxyコメントアウトした箇所を Dockerfile へ移動
DockerfileFROM plantuml/plantuml-server:jetty COPY ./docker-entrypoint-custom.sh /docker-entrypoint-custom.sh※ 公式の https://www.plantuml.com/plantuml に合わせる対応
docker-entrypoint-custom.sh#!/bin/sh mv /var/lib/jetty/webapps/ROOT.war /var/lib/jetty/webapps/plantuml.war exec /docker-entrypoint.sh "$@"quickchart
docker-compose.ymlversion: '3' services: quickchart: image: ianw/quickchart container_name: quickchart restart: always environment: - TZ=Asia/Tokyo - VIRTUAL_HOST=quickchart.docker - VIRTUAL_PORT=3400 - CERT_NAME=quickchart.docker networks: default: external: name: nginx-proxy事前準備
/etc/hosts+127.0.0.1 www.plantuml.docker +127.0.0.1 quickchart.docker
NoProxy+, *.docker
mkcert
(例: plantuml)shcd certs mkcert "*.plantuml.docker" plantuml.docker mv _wildcard.plantuml.docker+1-key.pem plantuml.docker.key mv _wildcard.plantuml.docker+1.pem plantuml.docker.crt
- 初回(無い場合)
shdocker network create --driver bridge nginx-proxy
ビルド(nginx-proxy, plantuml-server)
shdocker-compose build起動
shdocker-compose up -d
停止
shdocker-compose down -v --remove-orphansその他利用ツール類(参考)
- oldj/SwitchHosts: Switch hosts quickly!
- hostsファイル編集ツール
- Cntlmを使ってNTLMv2認証Proxy環境をやっつける - Qiita
- proxyツール
終わりに
リバースプロキシとそれ以外を分離しているので、network さえ繋げてしまえば他の docker 達も
environment
設定だけで勝手に振り分けてくれます!素晴らしい!shdocker network connect nginx-proxy {コンテナ名}モチロン上記の例の様に yaml ファイルで同名のネットワークを定義してもOK!
- 投稿日:2019-12-09T20:02:02+09:00
docker build を使わずコンテナイメージの中身をいぢる
ことの発端
docker image ls
で表示される IMAGE ID ってなんだろう?$ docker image ls # ↓ これ REPOSITORY TAG IMAGE ID CREATED SIZE prom/prometheus latest 7317640d555e 3 weeks ago 130MB alpine latest 965ea09ff2eb 6 weeks ago 5.55MBこちらの記事で「Copy On Write(COW)ファイルシステム」という要素技術を知りました。
コンテナ技術入門 - 仮想化との違いを知り、要素技術を触って学ぼう - エンジニアHub|若手Webエンジニアのキャリアを考える!
Dockerコンテナを作成する際に、そのベースファイルシステムとなるDockerイメージはOverlayFSのようにレイヤを重ね合わせた形で提供されています。ベースとなるOSレイヤ、そこにアプリケーションに必要なツールやライブラリをインストールしたレイヤ、さらにアプリケーションをインストールしたレイヤなど、複数のレイヤを重ね合わせてDockerイメージとなります。
これを知ると IMAGE ID について憶測ができます。
- IMAGE ID はレイヤごとのファイル差分の digest 値に関係するのでは?
- しかし単一レイヤの digest 値では Dockerfile の FROM が何であるかにかかわらず同じになってしまう。全レイヤのファイルか digest 値を合算した後さらに digest した値では?
- もしも IMAGE ID を偽った不正コンテナイメージが流通できるとしたら問題がある。Docker には IMAGE ID の検証機能と不正なコンテナイメージを拒絶する仕様があるのでは?
わたし、気になります!
調べてみよう・やってみよう
- docker の IMAGE ID 計算方法を調べる
- Linux コマンドで手作業でコンテナイメージをビルドする
- IMAGE ID そのままで中身を改ざんすると docker はどのような挙動をするか調べる
今回はこのあたりまでやってみたいと思います。
検証環境
- ハードウェア: Pixelbook (Chromebook)
- OS: Debian GNU/Linux 9 (stretch) Linux on Chromebook
- Docker CE: 19.03.5
- Storage Driver: btrfs
まだちょっとマイナーな Linux on Chromebook です。
参考資料
docker CE のコードを全部読んで把握できればすべて理解できるでしょうが、まったく取っ掛かりがないので docker build とか docker image id などで検索してみます。すると、とても参考になる Qiita の記事に出会いました。
イメージの構造がわからない状態で読み始めると辛くなるので
先にOCI image-specを読むことをオススメします。
なぜOCIかというと、Dockerのドキュメントより仕様としてしっかりまとまっているのと、
Dockerを参考にしているのもあって大枠は一致しているからです。なるほど!
仕様を読む前にとりあえず不正なコンテナを食わせてみる
この手のイメージファイルは tar で固めてあるのが定番なので、
docker save
でコンテナイメージをファイルとして取得してから展開する- ファイルシステムをいぢる
- どこかにあるだろうマニフェストの類はいぢらない
- tar で固める。これで不正なコンテナイメージの一丁上がり (たぶん)
docker load
で食わせるという操作をすれば docker が不正なイメージを拒絶するかどうかはわかるでしょう。 (たぶん)
かんたんな元イメージを build
hogehoge と書かれたファイル hogehoge を alpine の /tmp にコピーしただけのイメージを作ります。
DockerfileFROM alpine:latest COPY hogehoge /tmp/ # hogehoge は echo 'hogehoge' >| hogehoge で予め作っておきます$ docker build . -t hogehoge:latest Sending build context to Docker daemon 3.072kB Step 1/2 : FROM alpine:latest ---> 965ea09ff2eb Step 2/2 : COPY hogehoge /tmp/ ---> 4936a59b94ad Successfully built 4936a59b94ad Successfully tagged hogehoge:latest $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE hogehoge latest 4936a59b94ad 27 seconds ago 5.55MBIMAGE ID は
4936a59b94ad
ですね。
念の為コンテナを走らせて、/tmp/hogehoge の内容を確認しておきます。$ docker run -it hogehoge:latest /bin/sh / # cat /tmp/hogehoge hogehogeイメージをファイルに save して展開
$ docker save hogehoge:latest > hogehoge.tgz ls -lh 合計 5.6M -rw-r--r-- 1 weakboson weakboson 39 12月 7 21:44 Dockerfile -rw-r--r-- 1 weakboson weakboson 9 12月 8 18:33 hogehoge -rw-r--r-- 1 weakboson weakboson 5.6M 12月 8 20:37 hogehoge.tgz $ mkdir image $ tar xf hogehoge.tgz -C image # 後でわかりますが tar + gzip ではなく tar でした $ cd image $ ls -lh 合計 12K drwxr-xr-x 1 weakboson weakboson 40 12月 8 20:32 0d27994a6e9f841bf6a9973941008b303a7234d70c640570d70148b5b5d2a3d0 drwxr-xr-x 1 weakboson weakboson 40 12月 8 20:32 2ce302b70292e3484f04aa768fde2c54a93c208b28e205ffda9e373ffd40a575 -rw-r--r-- 1 weakboson weakboson 1.7K 12月 8 20:32 4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9.json -rw-r--r-- 1 weakboson weakboson 281 1月 1 1970 manifest.json -rw-r--r-- 1 weakboson weakboson 91 1月 1 1970 repositoriesお。さっそく manifest.json ともう一つ IMAGE ID の由来になってそうな
4936a59b94ad..(中略).json
というファイルがあります。このようなファイルがあれば sha256 digest をとりたくなるのが人の性 (サガ)$ sha256sum 4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9.json 4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9 4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9.jsonファイル名と sha256 digest が一致しますね。
2 つの json はなんだろう?
manifest.json[ { "Config": "4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9.json", "RepoTags": [ "hogehoge:latest" ], "Layers": [ "2ce302b70292e3484f04aa768fde2c54a93c208b28e205ffda9e373ffd40a575/layer.tar", "0d27994a6e9f841bf6a9973941008b303a7234d70c640570d70148b5b5d2a3d0/layer.tar" ] } ]manifest.json にはもう一方の json ファイル名とサブディレクトリにある tar ファイル、そしてコンテナイメージ名とラベルがあります。もう一方の json ファイルが Config というキーにあるので、仮に Config.json と表記します。
Config.json{ "architecture": "amd64", "config": { "Hostname": "", // 中略 "Image": "sha256:965ea09ff2ebd2b9eeec88cd822ce156f6674c7e99be082c7efac3c62f3ff652", // 中略 }, "container_config": { // 中略 "Cmd": [ "/bin/sh", "-c", "#(nop) COPY file:ee9321d69eb59158edcb22888b3c6665be5c9230a5713a2bfeb0f069358e86f8 in /tmp/ " ], // 中略 "Image": "sha256:965ea09ff2ebd2b9eeec88cd822ce156f6674c7e99be082c7efac3c62f3ff652", // 中略 "os": "linux", "rootfs": { "type": "layers", "diff_ids": [ "sha256:77cae8ab23bf486355d1b3191259705374f4a11d483b24964d2f729dd8c076a0", "sha256:dbdb51e45bed7ab135ee0050a34ce75f64dee736c78c936e20bbe0f7a02d6b33" ] } }Config.json には自身の sha256 digest が何回かと、 diff_ids という sha256 digest 値が2種登場します。
……直感ですがサブディレクトリにある tar ファイルが怪しいと思います。
サイズと sha256 digest 値を見てみましょう。$ ls -lh */layer.tar -rw-r--r-- 1 weakboson weakboson 2.5K 12月 8 20:32 0d27994a6e9f841bf6a9973941008b303a7234d70c640570d70148b5b5d2a3d0/layer.tar -rw-r--r-- 1 weakboson weakboson 5.6M 12月 8 20:32 2ce302b70292e3484f04aa768fde2c54a93c208b28e205ffda9e373ffd40a575/layer.tar $ sha256sum */layer.tar dbdb51e45bed7ab135ee0050a34ce75f64dee736c78c936e20bbe0f7a02d6b33 0d27994a6e9f841bf6a9973941008b303a7234d70c640570d70148b5b5d2a3d0/layer.tar 77cae8ab23bf486355d1b3191259705374f4a11d483b24964d2f729dd8c076a0 2ce302b70292e3484f04aa768fde2c54a93c208b28e205ffda9e373ffd40a575/layer.tarお。2ファイルの digest 値が diff_ids それぞれと一致しました。
ところで
layer.tar
ってもう見るからにレイヤのファイルシステムアーカイブっぽいですよね。サイズが大きな2ce302b70292(中略)/layer.tar
が FROM であるalpine:latest
だとすると、小さい0d27994a6e9f(中略)/layer.tar
を展開したら /tmp/hogehoge が出てきそうだと思いませんか?layer.tar を展開する
$ ls -lh 合計 12K -rw-r--r-- 1 weakboson weakboson 3 12月 8 20:32 VERSION -rw-r--r-- 1 weakboson weakboson 1.3K 12月 8 20:32 json -rw-r--r-- 1 weakboson weakboson 2.5K 12月 8 20:32 layer.tar $ mkdir layer $ tar xf layer.tar -C layer $ find layer layer layer/tmp layer/tmp/hogehoge $ cat layer/tmp/hogehoge hogehogeあたりです!
ところで VERSION と json も見てみましょう。
VERSION1.0json{ "id": "0d27994a6e9f841bf6a9973941008b303a7234d70c640570d70148b5b5d2a3d0", "parent": "2ce302b70292e3484f04aa768fde2c54a93c208b28e205ffda9e373ffd40a575", "created": "2019-12-08T11:32:35.014345961Z", // 中略 "Cmd": [ "/bin/sh", "-c", "#(nop) COPY file:ee9321d69eb59158edcb22888b3c6665be5c9230a5713a2bfeb0f069358e86f8 in /tmp/ " ], // 後略id は layer.tar のあるサブディレクトリ名で parent はもう一方、alpine だと踏んでいる方のディレクトリ名ですね。それに Dockerfile に記述したコマンドらしきものも見えます。
悪いことしましョ
内容を改ざんして json 類はそのままでパックし直します。
まず展開した layer 中の /tmp/hogehoge の内容を fugafuga に書き換えます。
$ cd layer $ echo 'fugafuga' >| tmp/hogehoge $ cat tmp/hogehoge fugafuga展開用に自作したサブディレクトリをお掃除しつつ tgz にパックします。
layer.tar
は名前からして gzip かけてないようですから無圧縮にします。$ tar cf ../layer.tar ./* $ cd ../ $ rm -rf layer $ cd ../ $ tar czf ../fugafuga.tgz ./* $ cd ../ $ ls -lh *.tgz -rw-r--r-- 1 weakboson weakboson 2.6M 12月 8 21:24 fugafuga.tgz -rw-r--r-- 1 weakboson weakboson 5.6M 12月 8 20:37 hogehoge.tgzあれ?だいぶサイズが違いますね……まあいいか。(イメージは正しくは gzip しない tar でした。)
そしておもむろに docker に食わせたいのですが、各種 json ファイル中の sha256 digest が変わっていないせいでしょうか?すぐに食べさせても何も起こりません。
一度 docker が持っているイメージを削除します。先程確認のために起動したコンテナも先に消します。$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5251c56e7b95 4936a59b94ad "/bin/sh" 55 minutes ago Exited (0) 54 minutes ago infallible_rubin $ docker container rm 5251c56e7b95 5251c56e7b95 $ docker image rm hogehoge:latest Untagged: hogehoge:latest Deleted: sha256:4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9食らえ!(食べないでー)
さあ、改めて召し上がれー♪
$ docker load -i fugafuga.tgz dbdb51e45bed: Loading layer [==================================================>] 10.24kB/10.24kB invalid diffID for layer 1: expected "sha256:dbdb51e45bed7ab135ee0050a34ce75f64dee736c78c936e20bbe0f7a02d6b33", got "sha256:4a64864cd5b3e1ac07d0b47eaf126746ba59e95897094527788502ebca556db2"はい、ペッと吐き出してくれました!偉いぞ docker!
docker load は内容が改ざんされたコンテナイメージを受け付けない!
人力 docker build 前に OCI の仕様にあたってみよう
OCI Image Format リポジトリを "image id" や先ほど docker が改ざんイメージをペッと吐き出したエラーに表示された "diffID" で検索すると OCI Image Configuration という Markdown で書かれた仕様が見つかります。
この仕様を読むと Config.json と表記していたファイルは OCI では Image JSON とか configuration json と呼ぶようで、たしかにこのファイルの sha256 digest が Image ID になるようです。
ImageID
Each image's ID is given by the SHA256 hash of its configuration JSON.
It is represented as a hexadecimal encoding of 256 bits, e.g.,sha256:a9561eb1b190625c9adb5a9513e72c4dedafc1cb2d4c5236c9a6957ec7dfd5a9
.
Since the configuration JSON that gets hashed references hashes of each layer in the image, this formulation of the ImageID makes images content-addressable.↲まとめると以下のようなことが書かれていると理解しました。
- Docker の IMAGE ID は configuration json (Image JSON) の sha256 digest 値
- Configuration json は各レイヤーの Layer DiffID を持つ
- Layer DiffID はレイヤーごとの非圧縮 tar アーカイブの sha256 digest 値
Let's 人力 docker build
Digest 値を正しく修正する
- "/tmp/hogehoge" の内容を修正した後の tar から Layer DiffID を計算
- configuration json 中の diff_id を計算値に置換
- configuration json の digest 値を計算
- configuration json を新しい digest 値でリネーム
- manifest.json 中の configuration json ファイル名を計算値に置換
4, 5 の操作は OCI の image-spec.md と manifest.md には記述されていないように読めましたが、docker イメージ中の manifest.json には対応があるので念のため修正しました。 (修正しないでも動作するかは未検証です。)
# 0. 置換用に前の Layer DiffID を退避 $ OLD_DIGEST=dbdb51e45bed7ab135ee0050a34ce75f64dee736c78c936e20bbe0f7a02d6b33 # 1. "/tmp/hogehoge" の内容を修正した後の tar から Layer DiffID を計算 $ NEW_DIGEST=`sha256sum 0d27994a6e9f841bf6a9973941008b303a7234d70c640570d70148b5b5d2a3d0/layer.tar | awk '{print $1}'` $ echo $NEW_DIGEST 4a64864cd5b3e1ac07d0b47eaf126746ba59e95897094527788502ebca556db2 # 2. configuration json 中の diff_id を計算値に置換 $ sed -i "s/${OLD_DIGEST}/${NEW_DIGEST}/g" 4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9.json $ OLD_IMAGE_ID=4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9 # 3. configuration json の digest 値を計算 $ NEW_IMAGE_ID=`sha256sum 4936a59b94ad4d2c2a4bce855e7891276f4c2b3fb3b25dbe3b2774ae4185d6e9.json| awk '{print $1}'` $ echo $NEW_IMAGE_ID 53667683a1bc3a9de27dbb96457ba102d4cd9dc6a78cba9a534b3d626fe2ff63 # 4. configuration json を新しい digest 値でリネーム $ mv ${OLD_IMAGE_ID}.json ${NEW_IMAGE_ID}.json # 5. manifest.json 中の configuration json ファイル名を計算値に置換 $ sed -i "s/${OLD_IMAGE_ID}/${NEW_IMAGE_ID}/g" manifest.jsonDigest 値が正統な Image tgz を作成して docker に食わせる
$ tar czf ../fugafuga.tgz ./* $ cd ../ $ docker load -i fugafuga.tgz 4a64864cd5b3: Loading layer [==================================================>] 10.24kB/10.24kB Loaded image: hogehoge:latestお!食べてくれましたね……
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE hogehoge latest 53667683a1bc 4 hours ago 5.55MB他のメタ情報を修正していないので CREATED は hogehoge を docker build した時刻になっているようです。中身はきちんと hogehoge -> fugafuga が反映されているでしょうか?起動できるでしょうか?
$ docker run -it hogehoge:latest /bin/sh / # cat /tmp/hogehoge fugafugaいけました!内容を変更後も IMAGE ID を正しく計算・設定すると docker で扱えます!
まとめ
- docker の IMAGE ID は configuration json (Image JSON) の sha256 digest 値です。configuration json はさらに各レイヤの Layer DiffID という sha256 digest 値を持ちます
- レイヤを改ざんして IMAGE ID 計算時と内容が変わったイメージは docker load できません
- レイヤを変更しても正しく IMAGE ID を計算・設定したイメージは docker load, run できます (docker build 自身がやってることの最低限の操作に相当するのでしょう)
続けて調べたいこと
イメージサイズが大きなサイドカーコンテナを過剰に忌避するものでもないのか検証する
同じホストで同じ構成のコンテナを複数作成する場合、各コンテナ同士では多くの共有可能なバイナリやライブラリがあります。コンテナごとにファイルシステムをまるごと用意する、とはディスクスペースを無駄に消費していることと同義なのです。また、大きな環境の場合、ファイルシステムの作成にも時間がかかりコンテナの起動が遅くなってしまう可能性もあります。こうした無駄を改善するのが、COW(Copy On Write)ファイルシステムです。
コンテナ技術入門 - 仮想化との違いを知り、要素技術を触って学ぼう - エンジニアHub|若手Webエンジニアのキャリアを考える! から引用
最近 Kubernetes でアプリ運用をするにあたり Envoy や mtail のようなサイドカーコンテナのイメージサイズはできるだけ小さくしたいと考えていました。しかし今回の記事を書くために上記引用記事を再読して COW ファイルシステムの性質を再認識しました。
既存レイヤのファイルを変更しなければ1ワーカーノードにサイドカーコンテナがいくつあろうと1個分のディスクしか消費しないはずで、そうそうイメージのサイズにセンシティブにならなくてよいのかもしれません。意図的にイメージサイズが大きなコンテナを複数起動して検証してみようと思います。Docker CE の実装を読んでいぢってみる
今回 OCI の仕様書と試行錯誤で動作できてしまったので Docker のコードをまーーーったく読みませんでした。Docker のコードを読んで改修してみて、例えば Image ID 詐称イメージでも食う docker とかビルドしてみたいものです。今回は docker load でブロックされることを確認しましたが、おそらく docker のほとんどあらゆる機能にコンテナイメージの検証プロセスが含まれているのではと予想しています。
エラーメッセージで検索した感じ docker load をブロックしたコードはこのあたりかな?
https://github.com/docker/docker-ce/blob/d49c4ca453ce4d1161ce5fb2482be7538bf73e07/components/engine/image/tarexport/load.go#L119-L121明日は @hazanyaan の「Web脆弱性を体感してみよう」です。
- 投稿日:2019-12-09T17:02:48+09:00
Dockerを使用してNuxt.jsアプリを作成して実行する
Use Docker to Create and Run a Nuxt.js App
このチュートリアルではUbuntu 19.04を使用しています。
I`m using Ubuntu 19.04 for this tutorial.
一時コンテナを実行してnuxt.jsアプリを作成します
run temporary container to create nuxt.js app
sudo docker container run -it -v $(pwd):/app -w /app node:12.13.1-alpine /bin/shコンテナ内に、「nuxt」と「nuxt-create-app」をインストールします
Inside container, install
nuxt
andnuxt-create-app
npm install --save nuxt npm install -g create-nuxt-app完了したら、Nuxtアプリを作成できます
Once done, you can create the Nuxt app
npx create-nuxt-app <project-name>それが完了したら、コンテナを「exit」し、プロジェクトフォルダの所有者を変更できます
Once that is done, you can
exit
the container, change the owner of the project foldersudo chown -R myuser:myuser <project-name>プロジェクトフォルダーに「cd」し、「Dockerfile」と「docker-compose.yml」の両方を作成します
cd
into the project folder and create both theDockerfile
anddocker-compose.yml
Dockerfile
FROM node:12.13.1-alpine WORKDIR /app RUN apk update && \ apk add git && \ npm install -g npm && \ npm install -g @vue/cli \ npm install --save nuxt ENV HOST 0.0.0.0 EXPOSE 3000問題がないように、Dockerコンテナの同じバージョンを最初から使用することを忘れないでください。
Remember to use the same version from the docker container from the beginning, as to not have issues.
docker-compose.yml
version: '3' services: nuxt: build: . tty: true command: npm run dev volumes: - .:/app ports: - "3000:3000"これにより、docker-composeを実行してプロジェクトをビルドおよび実行できます
With this, you can run docker-compose to build and run the project
sudo docker-compose up --build
コンテナーをダウンロードしてイメージをビルドするには、最初にしばらく時間がかかります。一度完了すると、プロジェクトのホームページがURL「localhost:3000」に表示されます
This will take a while the first time, in order to download the container and build the image, once done, you can see the project home page on the url
localhost:3000
- 投稿日:2019-12-09T16:27:48+09:00
dockerでgpuを使用するためのnvidia-docker2インストールガイド
概要
- dockerでGPUを用いるためにはnvidia-docker2のインストールが必要.
- nvidia-docker2のlinuxへのインストール方法が少々面倒だったので,自分用にメモ.
nvidia-docker2のインストール方法
installガイド# リポジトリの登録 curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \ sudo tee /etc/apt/sources.list.d/nvidia-docker.list sudo apt-get update # nvidia-docker2のインストール sudo apt-get install -y nvidia-docker2 sudo pkill -SIGHUP dockerd # 動作テスト docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smiこれで,dockerを起動する際にruntimeオプションを追加し,
--runtime=nvidia
と記述すればdocker内でGPUが認識されます.
- 投稿日:2019-12-09T15:43:03+09:00
Mojave で Docker Volume のバックアップ(Docker v19.03)
docker volume create
で作成したボリュームをローカルにバックアップしたい。しかし、Mac には
docker volume inspect
で表示されるMountpoint
にボリュームがない。また、
Docker Engine
のバージョンによって挙動が違うらしく、「mac
docker
volume
バックアップ
」で Qiita 記事をググっても記事の内容がバラバラで困った。簡単にバックアップ&復元できないか。TS;DR
Mac の
Docker Desktop
の場合、Alpine Linux
などの軽量コンテナに下記2つを一旦マウントしtar
などでアーカイブするのが楽です。(バックアップしたいボリューム名がdata-hoge
の場合)
- バックアップしたいボリューム(
-v data-hoge:/data
)- バックアップ先のディレクトリ(
-v $(pwd)/backup:/backup
)docker run --rm -v data-qithub:/data -v $(pwd)/backup:/backup alpine tar cvf /backup/backup.tar /data復元は上記の逆の手順で、アーカイブとボリュームをマウントして、ボリューム内に解凍します。
TL;DR
ボリュームの確認$ docker volume ls DRIVER VOLUME NAME local data-hogeバックアップ$ # バックアップ・ディレクトリの作成&移動 $ cd mkdir ~/my_backup && cd $_ $ # バックアップ開始 $ docker run --rm \ -v data-hoge:/data \ -v $(pwd)/backup:/backup \ alpine \ tar cvf /backup/backup.tar /data tar: removing leading '/' from member names data/ data/hello.txt ... $ # 作成されたバックアップの確認 $ ls backup $ # ディレクトリ構造 $ tree . └── backup └── backup.tar 1 directory, 1 fileアーカイブの解凍$ tar -xvf ./backup/backup.tar x data/ x data/hello.txt ... $ # 解凍ファイルの確認 $ ls backup data $ # ディレクトリ構造 . ├── backup │ └── backup.tar └── data ├── ... └── hello.txtMac の Docker ボリュームは特殊
docker volume create --name data-hoge
とボリュームを作成した場合、inspect
コマンドでボリューム情報を表示すると以下のようになります。ボリューム情報の表示$ docker volume inspect data-hoge [ { "CreatedAt": "2019-12-09T04:28:16Z", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/data-hoge/_data", "Name": "data-hoge", "Options": {}, "Scope": "local" } ]しかし、上記の
Mountpoint
のパスにデータがあるかと思いきや、ありません。Mountpointをlsしてみる$ ls /var/lib/docker/volumes/data-hoge/_data ls: /var/lib/docker/volumes/data-hoge/_data: No such file or directory $ # そもそも /var/lib/docker がない $ ls /var/lib/ postfixこれは Mac の場合は Docker は VM(仮想マシン) 上で動いているためです。つまり
docker volumes create
で作成されたボリュームも仮想マシンのイメージの中にされるということなので、ローカルには直接作成されません。Mac の場合、仮想マシンのイメージは以下のディレクトリになります。(
Docker v19.03.5
現在)Dockerの仮想マシン・イメージの保存先~/Library/Containers/com.docker.docker/Data/vms/0/問題は、このディレクトリから該当するイメージと、そこからデータを引き出す方法がわかりづらいこと。
どのファイルを選べばいいのかわからない$ tree ~/Library/Containers/com.docker.docker/Data/vms/0/ /Users/admin/Library/Containers/com.docker.docker/Data/vms/0/ ├── 00000002.000005f4 ├── 00000002.00001000 ├── 00000002.00001001 ├── 00000002.00001002 ├── 00000002.0000f3a4 ├── 00000002.0000f3a5 ├── 00000003.000005f5 ├── 00000003.00000948 ├── Docker.raw ├── config.iso ├── connect ├── data ├── guest.000005f5 -> 00000003.000005f5 ├── guest.00000948 -> 00000003.00000948 ├── hyperkit.json ├── hyperkit.pid ├── lifecycle-server.sock ├── log ├── nic1.uuid └── tty -> /dev/ttys000 2 directories, 18 files
screen
とtty
で仮想マシンに接続する方法もあるようなのですが、確認ができるというだけでローカルにデータを保存するには煩雑な作業が必要そうです。$ # 仮想マシンの tty に接続 $ screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty cd docker-desktop:~# # 仮想マシン上で Mountpoint を確認 docker-desktop:~# ls /var/lib/docker/volumes/data-qithub/_data hello.txt ... docker-desktop:~# # Ctrl+a -> Crtl+k で exit Really kill this window [y/n] y [screen is terminating]また、これらのファイルを下手に触ってイメージを壊したりするのも危険なので、確実で安全なバックアップ方法がないか探したところ、公式に書いてありました。ダミーのコンテナに、ボリュームとローカルのディレクトリをマウントして
tar
アーカイブする方法です。For example, create a new container named
dbstore
:$ docker run -v /dbdata --name dbstore ubuntu /bin/bashThen in the next command, we:
- Launch a new container and mount the volume from the
dbstore
container- Mount a local host directory as
/backup
- Pass a command that tars the contents of the
dbdata
volume to abackup.tar
file inside our/backup
directory.$ docker run --rm \ --volumes-from dbstore \ -v $(pwd):/backup \ ubuntu tar cvf /backup/backup.tar /dbdata(Backup, restore, or migrate data volumes @ docs.docker.com より)
確かにシンプルで確実な方法でした。なにより直感的です。
ちなみに、リカバリーは逆の手順で、ボリューム内に
tar
ファイルを解凍します。リカバリー方法$ # リカバリー用の空のボリューム作成 (dbstore2) $ docker volume create --name dbstore2 $ # リカバリー $ docker run --rm \ -v dbstore2:/dbdata \ -v $(pwd)/backup.tar:/backup/backup.tar \ ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"参考文献
- Docker for MacのDisk Imageの場所が変わった @ Qiita
- dockerのデータボリュームとそのバックアップ方法 @ Qiita
- Docker for Macのvolumesの場所 @ Qiita
- データ・ボリュームのバックアップ・修復・移行 | コンテナでデータを管理する @ Docker 1.9 beta 日本語ドキュメント
- 投稿日:2019-12-09T15:43:03+09:00
Mojave で Docker Volume のバックアップ(Docker v19.03, macOS 10.14)
docker volume create
で作成したボリュームをローカルにバックアップしたい。しかし、Mac には
docker volume inspect
で表示されるMountpoint
にボリュームがない。また、
Docker Engine
のバージョンによって挙動が違うらしく、「mac
docker
volume
バックアップ
」で Qiita 記事をググっても記事の内容がバラバラで困った。簡単にバックアップ&復元できないか。TS;DR
Mac の
Docker Desktop
の場合、Alpine Linux
などの軽量コンテナに下記2つを一旦マウントしtar
などでアーカイブするのが楽です。(以下は、バックアップしたいボリューム名がdata-hoge
の場合)
- バックアップしたいボリューム(
-v data-hoge:/data
)- バックアップ先のディレクトリ(
-v $(pwd)/backup:/backup
)docker run --rm -v data-hoge:/data -v $(pwd)/backup:/backup alpine tar cvf /backup/backup.tar /data復元は上記の逆の手順で、アーカイブとボリュームをマウントして、ボリューム内に解凍します。
TL;DR
ボリュームの確認$ docker volume ls DRIVER VOLUME NAME local data-hogeバックアップ$ # バックアップ・ディレクトリの作成&移動 $ cd mkdir ~/my_backup && cd $_ $ # バックアップ開始 $ docker run --rm \ -v data-hoge:/data \ -v $(pwd)/backup:/backup \ alpine \ tar cvf /backup/backup.tar /data tar: removing leading '/' from member names data/ data/hello.txt ...アーカイブの解凍と確認$ cd ~/my_backup $ # 作成されたバックアップの確認 $ ls backup $ # ディレクトリ構造の確認 $ tree . └── backup └── backup.tar 1 directory, 1 file $ $ # アーカイブの解凍 $ tar -xvf ./backup/backup.tar x data/ x data/hello.txt ... $ # 解凍ファイルの確認 $ ls backup data $ # ディレクトリ構造の確認 $ tree . ├── backup │ └── backup.tar └── data ├── ... └── hello.txtMac の Docker ボリュームは特殊
docker volume create --name data-hoge
とボリュームを作成した場合、inspect
コマンドでボリューム情報を表示すると以下のようになります。ボリューム情報の表示$ docker volume inspect data-hoge [ { "CreatedAt": "2019-12-09T04:28:16Z", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/data-hoge/_data", "Name": "data-hoge", "Options": {}, "Scope": "local" } ]しかし、上記の
Mountpoint
のパスにデータがあるかと思いきや、ありません。Mountpointをlsしてみる$ ls /var/lib/docker/volumes/data-hoge/_data ls: /var/lib/docker/volumes/data-hoge/_data: No such file or directory $ # そもそも /var/lib/docker がない $ ls /var/lib/ postfixこれは Mac の場合は Docker は VM(仮想マシン) 上で動いているためです。つまり
docker volumes create
で作成されたボリュームも仮想マシンのイメージの中に作成されるということなので、ローカルには直接作成されません。Mac の場合、仮想マシンのイメージは以下のディレクトリになります。(
Docker v19.03.5
現在)Dockerの仮想マシン・イメージの保存先~/Library/Containers/com.docker.docker/Data/vms/0/問題は、このディレクトリから該当するイメージと、そこからデータを引き出す方法がわかりづらいこと。
どのファイルを選べばいいのかわからない(treeコマンドはbrewで別途インストール済み)$ tree ~/Library/Containers/com.docker.docker/Data/vms/0/ /Users/admin/Library/Containers/com.docker.docker/Data/vms/0/ ├── 00000002.000005f4 ├── 00000002.00001000 ├── 00000002.00001001 ├── 00000002.00001002 ├── 00000002.0000f3a4 ├── 00000002.0000f3a5 ├── 00000003.000005f5 ├── 00000003.00000948 ├── Docker.raw ├── config.iso ├── connect ├── data ├── guest.000005f5 -> 00000003.000005f5 ├── guest.00000948 -> 00000003.00000948 ├── hyperkit.json ├── hyperkit.pid ├── lifecycle-server.sock ├── log ├── nic1.uuid └── tty -> /dev/ttys000 2 directories, 18 files
screen
とtty
で仮想マシンに接続する方法もあるようなのですが、確認ができるというだけでローカルにデータを保存するには煩雑な作業が必要そうです。$ # 仮想マシンの tty に接続 $ screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty cd docker-desktop:~# # 仮想マシン上で Mountpoint を確認 docker-desktop:~# ls /var/lib/docker/volumes/data-qithub/_data hello.txt ... docker-desktop:~# # Ctrl+a -> Crtl+k で exit Really kill this window [y/n] y [screen is terminating]また、これらのファイルを下手に触ってイメージを壊したりするのも危険なので、確実で安全なバックアップ方法がないか探したところ、公式に書いてありました。ダミーのコンテナに、ボリュームとローカルのディレクトリをマウントして
tar
アーカイブする方法です。For example, create a new container named
dbstore
:$ docker run -v /dbdata --name dbstore ubuntu /bin/bashThen in the next command, we:
- Launch a new container and mount the volume from the
dbstore
container- Mount a local host directory as
/backup
- Pass a command that tars the contents of the
dbdata
volume to abackup.tar
file inside our/backup
directory.$ docker run --rm \ --volumes-from dbstore \ -v $(pwd):/backup \ ubuntu tar cvf /backup/backup.tar /dbdata(Backup, restore, or migrate data volumes @ docs.docker.com より)
確かにシンプルで確実な方法でした。なにより直感的です。
ただ、
ubuntu
コンテナを使うよりはalpine
の軽量コンテナを使った方が個人的に好みです。また、上記の方法だと処理後に不要になったダミー・コンテナが残ってしまいます。ボリュームが生きている(docker volume ls
で表示される)のであれば、以下のようにバックアップするのが簡単だと思います。ボリューム名がdbstoreの場合docker run --rm \ -v dbstore:/dbstore \ -v $(pwd)/backup:/backup \ alpine tar cvf /backup/backup.tar /dbstoreちなみに、リカバリーは逆の手順で、ボリューム内に
tar
ファイルを解凍します。リカバリー方法$ # リカバリー用の空のボリューム作成 (dbstore2) $ docker volume create --name dbstore2 $ # リカバリー $ docker run --rm \ -v dbstore2:/dbdata \ -v $(pwd)/backup.tar:/backup/backup.tar \ ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"参考文献
- Docker for MacのDisk Imageの場所が変わった @ Qiita
- dockerのデータボリュームとそのバックアップ方法 @ Qiita
- Docker for Macのvolumesの場所 @ Qiita
- データ・ボリュームのバックアップ・修復・移行 | コンテナでデータを管理する @ Docker 1.9 beta 日本語ドキュメント
- 投稿日:2019-12-09T15:10:49+09:00
Mattermostに仮想サーバのディスク空き容量お知らせBotを作る
富士通システムズウェブテクノロジー Advent Calendar 2019 11日目の投稿です。
(お約束)記事の内容は全て個人の見解であり、執筆内容は執筆者自身の責任です。所属する組織は関係ありません。
また、執筆者はSE一年目の新人のため、至らない点があればご指摘いただけると嬉しいです。初めに
仮想サーバのディスク容量って気が付いたらいっぱいになっていませんか?コマンドがTabキーで補完されなくなってから気づくと対応が面倒ですよね。
そこで、仮想サーバのディスク容量を指定した日時にチャットツールに通知するBotを作成しました。
前提条件
- 仮想サーバはエクストラネット環境
- ローカルはWindows10
- 使用OSSはDocker,Node-RED
- Mattermostのチーム管理者かシステム管理者になる
環境構築
まずは環境構築です。Docker上にNode-REDをインストールして、Node.jsを使えるように設定します。
手順
以下のURLからWindows10にDockers for Windowsをインストールします。
https://docs.docker.com/docker-for-windows/install/docker-compose設定ファイルのdocker-compose.ymlを作成します。
docker-compose.ymlの例version: '2' services: nodered: ports: - 8088:1880 volumes: - C:/xxx/Node-RED/nodered-data-pj:/data environment: - TZ=Asia/Tokyo - NODE_RED_ENABLE_PROJECTS=true image: nodered/node-red:latest restart: unless-stoppedWindows PowerShellを管理者として実行します。
docker-compose.ymlのあるフォルダ上で
docker-compose up -d
を実行し、バックグラウンドでコンテナを立ち上げます。
docker exec -it node-red_nodered_1 bash
コマンドを実行し、コンテナ内に入ります。コンテナ内で
npm install --save node-ssh
コマンドを実行して、node-sshをインストールします。
Node-REDの追加モジュールを利用するために、settings.jsを編集します。
settings.jsの編集例functionGlobalContext: { sensor:require('node-ssh') // os:require('os'), // jfive:require("johnny-five"), // j5board:require("johnny-five").Board({repl:false}) },
exit
コマンドを実行し、コンテナから出ます。
docker-compose restart
コマンドでアプリケーションを再起動します。Mattermostにディスク容量を通知するBot作成
Bot作成をします。前提としてチーム管理者かシステム管理者でないとウェブフックを追加できないため、権限のある人に依頼しましょう。
事前準備
Mattermostのメインメニューから統合機能を選択します。
統合機能のメニューから内向きのウェブフックを追加します。
ウェブフックを編集します。タイトルと説明を入力してください。
※チャンネルはペイロードで制御するため入力不要です。手順
環境構築のdocker-compose.ymlで指定したポートを入力して、Node-REDに入ります。
※Node-REDの基本的な使い方に関してはこちらの記事を参考にしました。
Node-RED超入門injectノードでBotを流す日時の設定をします。
functionノードに、仮想サーバ内にSSH接続してディスク容量確認コマンドを実行するコードを書きます。node.jsasync function main() { const node_ssh = global.get("sensor"); const ssh = new node_ssh(); const sshPassword = '********'; // 接続 await ssh.connect({ host: 'XXX.XX.XX.XX', port: 22, username: '****', password: sshPassword }); // コマンド実行 msg.ssh = await ssh.execCommand('df -H', {options: {pty: true}}); // 切断 ssh.dispose(); node.send(msg); } main();functionノードに、MattermostにBotとしてメッセージを流すコードを書きます。
node.jsmsg.payload = {}; msg.payload.icon_url = "https://xxxxxxxx/xxxxxxxxxxxx"; msg.payload.username = "ディスク空き容量お知らせ"; msg.payload.text = "@xxx.xxx\n```\n"+msg.ssh.stdout+"\n```"; msg.payload.channel = "xxxx" msg.url = "https://mattermost.xxx/hooks/xxxxxxxxxxxxxxxxxxxx"; return msg;※msg.payload.textの@XXX.XXXはメンションです。
http requestノードの、SSL/TLS接続を有効化チェックボックスにチェックを入れ、Mattermostの証明書を設定します。
すべてのノードをつなぎ、右上のデプロイボタンを押下して終了です!
※debugノードの対象をmsgオブジェクト全体にして動作確認を行いました。Botと同じ内容をメールにも送る方法
Botと同じ内容をメールで送る方法についての説明です。
手順
画面右上のメインメニューから、パレットの管理を選択します。
ノードを追加タブで、mailと入力して検索します。
node-red-node-emailを選んでノードを追加し、メール送信ができるようにします。
functionノードに送信したい内容や件名等を書き、ディスク容量確認コマンドを実行するノードとつなげます。node.jsmsg.payload = msg.ssh.stdout; msg.topic = "【Node-RED】ディスク空き容量お知らせ"; return msg;接続部が左側にあるemailノードを選び、宛先、サーバ、ポートなどを入力し、ディスク容量確認コマンドを実行するノードとつなげます。
デプロイして終了!設定した日時にメールが届きます。
- 投稿日:2019-12-09T14:28:49+09:00
Docker-composeで解析(RNAseq)
Docker-composeで解析(RNAseq)
これを見ればあなたもすぐにRNAseq解析ができる!!
※Dockerインストール済みの場合前回に引き続き、解析ツールをDocker-composeで作成してみた。
Docker-composeを使ってみよう今回やりたいこと
RNAseq解析
docker-composeでsraファイルをbamファイルにしてみせます。手順
sra ↓(parallel-fastq使用) fastq ↓(fastp使用) trim.fastq ↓(STAR使用) bamファイル (全てbiocontainerのコンテナを使用)biocontainersのリポジトリURL:biocontainers
内容としては、下記リンクのスクリプトと同様のことができます。※exec_bam2readcount_STAR.Rを除く。
下記スクリプトを動かすためには様々なパッケージのインストールが必要になりますね・・・。
GitHub:https://github.com/petadimensionlab/STAR参考URL:
RNAseq解析について:遺伝子発現量解析RNA-Seq持ち物・下準備
・リードデータ(SRR7508944.sra)
・genome
・アノテーションファイル
をホストPC内任意のディレクトリに保存。(ディレクトリ構成は下記の通り 参照)
※今回の対象データ:SRR7508944・genomeとアノテーションファイル名を同じ名前に変更しておこう。
例)genome=TAIR10.fa、annotation=TAIR10.gff3参考URL:
持ち物の中身の詳細:STAR による RNA-Seq リードのマッピングSTAR (A. thaliana, paired-end RNA-Seq)ディレクトリ構成は下記の通り
.(/yourlocal_dir) ├── docker-compose.yml ├── .env ├── input/ # リードデータ.sra保存 ├── (output/) # 解析結果の出力ファイル用ディレクトリ(docker-composeをスタートさせると作成) └── STARidx/ #genome、アノテーション保存 (STARindexの保存先)Docker-compose.yml 作成
docker-compose.ymlの中身
docker-compose.yml#env in .env file version: "3" services: parallel-fastq: image: quay.io/biocontainers/parallel-fastq-dump:${VER_1} container_name: parallel-fastq tty: true volumes: - ${DIR}:/tmp/wk working_dir: /tmp/wk command: > bash -c "parallel-fastq-dump --sra-id input/${ID}.sra --threads ${THREADS} --split-files --gzip && mkdir -p output/${ID} && mv *.fastq.gz output/${ID}/" fastp: image: quay.io/biocontainers/fastp:${VER_2} container_name: fastp tty: true volumes: - ${DIR}:/tmp/wk working_dir: /tmp/wk command: sh wait-for-it.sh output/${ID}/${ID}_1.fastq.gz fastp -w ${THREADS} -h output/${ID}/${ID}.html -j output/${ID}/${ID}.json -i output/${ID}/${ID}_1.fastq.gz -I output/${ID}/${ID}_2.fastq.gz -o output/${ID}/${ID}_trim_paired_1.fastq.gz -O output/${ID}/${ID}_trim_paired_2.fastq.gz star: image: quay.io/biocontainers/star:${VER_3} container_name: star tty: true volumes: - ${DIR}:/tmp/wk working_dir: /tmp/wk command: > bash -c "sh wait-for-it.sh output/${ID}/${ID}.html STAR --runThreadN ${THREADS} --runMode genomeGenerate --genomeDir STARidx --genomeFastaFiles STARidx/${SPECIES}.fa --sjdbGTFfile STARidx/${SPECIES}.gff3 ${STARidxopt} && STAR --runThreadN ${THREADS} --readFilesCommand gunzip -c --genomeDir STARidx --readFilesIn output/${ID}/${ID}_1.fastq.gz output/${ID}/${ID}_2.fastq.gz --outFileNamePrefix output/${ID}/${ID}. ${STARopt}".envの中身
.envVER_1=0.6.5--py_0 #バージョン VER_2=0.20.0--hdbcaa40_0 #バージョン VER_3=2.7.1a--0 #バージョン THREADS=6 #スレッド DIR=/yourlocal_dir #ローカルのディレクトリ ID=SRR7508944 #対象データのID SPECIES=TAIR10 #対象データの種類 STARidxopt=--sjdbOverhang 100 --genomeSAindexNbases 12 #STARコマンドのオプション STARopt=--outFilterMultimapScoreRange 1 --outFilterMultimapNmax 10 --outFilterMismatchNmax 5 --alignIntronMax 500000 --alignMatesGapMax 1000000 --sjdbScore 2 --alignSJDBoverhangMin 1 --genomeLoad NoSharedMemory --limitBAMsortRAM 0 --outFilterMatchNminOverLread 0.33 --outFilterScoreMinOverLread 0.33 --sjdbOverhang 100 --outSAMstrandField intronMotif --outSAMattributes NH HI NM MD AS XS --outSAMunmapped Within --outSAMtype BAM Unsorted --outSAMheaderHD @HD VN:1.4 #STARコマンドのオプションさて、docker-compose.ymlの解説です。
ざっくり解説すると、
3つのコンテナイメージをコンテナ化し (=parallel-fastq・fastp・star)
マウントするディレクトリはどれも同じで (=ホストは.envに記載した”/yourlocal_dir”・コンテナはそれぞれtmp/wk)
それぞれコマンドを与えている。(=それぞれcommand以下に記述)それぞれのコマンドのざっくり解説は下記にて。
内容→SRA Toolkitのfastq-dumpを並列実行して高速化する parallel-fastq-dump
・parallel-fastq SRR7508944.sra から SRR7508944_1.fastq.gz・SRR7508944_2.fastq.gz を出力。・fastp SRR7508944_1.fastq.gz・SRR7508944_2.fastq.gz から SRR7508944_trim_paired_1.fastq.gz・SRR7508944_trim_paired_2.fastq.gz・SRR7508944.json・SRR7508944.html を出力。・star 1. index作成。 2. SRR7508944_trim_paired_1.fastq.gz・SRR7508944_trim_paired_2.fastq.gz から SRR7508944.Aligned.out.bam・そのたlogファイル を出力。sraファイルがbamファイルになりましたね。
動かしてみよう!
genomeとか探すんめんどくせ。って方、下記Githubからどぞー!
.env の/yourlocal_dir
を変更するだけ!
※sraは容量でかいのでアップロードできませんでした。自力でダウンロードしてください。(docker run --rm -v /yourlocal_dir/Docker_compose_STAR/input:/root/ncbi/public/sra inutano/sra-toolkit prefetch SRR7508944
でダウンロードできます。)Github:https://github.com/petadimensionlab/Docker_compose_STAR
動かし方
まず、docker-conpose.ymlのあるディレクトリに移動。
cd /yourlocal_dir
起動
イメージがない場合は自動でインストールしてくれます。
docker-compose up -d
logをみる。
途中経過もわかる。
docker-compose logs
終わったらおしまい。
いらないので捨てましょう。
docker-compose rm -f
これであなたもRNAseq解析ができた(はず)!!
もっと詳しくDocker-compose.ymlを知りたい方
fastpとstarのcommandに書いてる
wait-for-it.sh
ってなに?→順番にコンテナのコマンドが動作するようにシェルスクリプトです。(いっぺんにコンテナが動き出すといろいろやばいです。)
wait-for-it.shの中身
wait-for-it.sh#!/bin/sh set -e waitfile="$1" shift cmd="$@" until test -e $waitfile do >$2 echo "Waiting for file [$waitfile]." sleep 1 done >&2 echo "Found file [$waitfile]." exec $cmdcommand記入例
コンテナ①: (略) command: touch test.txt コンテナ②: (略) command: sh wait-for-it.sh test.txt touch test2.txt説明:コンテナ①でできる予定のファイル(text.txt)の存在を確認するまでコンテナ②は待機、ファイル(text.txt)見つけたら指定したコマンド(touch test2.txt)動かす。
参考URL:docker-composeでDBの起動完了を待ってからWebアプリを実行する
tty: ture ってなに?
→起動したコンテナが落ちないようにするためです。
参考URL:docker-compose up したコンテナを起動させ続ける方法
そのた
STARを使用しているので、PCのメモリ・CPUをよく確認して動かしましょう。
→仮想環境でも自分のPCのスペック以上のことはできません。。。スペック最強PC!!なのに動きません。
→Dockerの設定を変更しましょう。
右上(Macの場合)のクジラクリック→Preferences → Advancedで設定できます。
参考URL: macOSでDocker環境構築7.おまけのおまけ
沢山sampleがデータあるとき用のpythonスクリプトを作成しました。
このpythonを動かしてほったらかしにできますzzz(( _ _ ))..zzzZZ
※ついでにSRAデータもinsallできる特典付き!!
※まさかの未完!!(失敗したので工事中
)
おわり
おわりではないけどおわり。
工事終了しましたら、「おまけのおまけ」が更新されます。
- 投稿日:2019-12-09T14:13:40+09:00
Railsコンソールで日本語入力ができない現象【Docker】
はじめに
Railsの参考書を読みながら勉強を進めているときに、
DockerのRailsコンテナ内で、Railsコンソールを起動し、日本語文章を入力しようとしたら、
入力はできるのに、エンターキーを押すとターミナルに表示されないという現象が起きたので、その解決方法についてです。
解決方法
DockerFileに、
ENV LANG C.UTF-8
を記入して
docker-compose up --build
で再起動これでコンソールに日本語を入力できるようになります。
参考にしたページ:Docker / rails console で日本語入力できない問題
https://gist.github.com/tasiyo7333/2163a09129ed36639645145a0146d8d3
- 投稿日:2019-12-09T14:13:23+09:00
Docker-composeを使ってみよう
Docker-compose とは
ちょっと調べてみました。
複数のDockerコンテナをまとめて自動化・管理するツールらしい。
連携(コンテナ間のネットワーク連携)もできるらしい。参考URL:
Docker compose ことはじめハンズオンDocker-compose インストール
Docker Desktop for Mac でDockerをinstallした場合は不要。(Windowsも同じく)
Linuxの場合は上記参考URLを参照。(丸投げ)Docker-compose.yml 作成
ディレクトリ構成は下記の通り
.(/yourlocal_dir) ├── .env ├── Dockerfile ├── docker-compose.yml ├── input/ ├── output/ └── script/docker-compose.ymlの基本のき
「見本のdocker-conpose.yml」
docker-conpose.ymlversion: "3" # バージョン services: # 起動するコンテナの定義 ubuntu: image: ubuntu:16.04 # 使いたいイメージをinstall container_name: ubuntu # コンテナの名前 volumes: - /yourlocal_dir:/tmp/wk #hostとマウント working_dir: /tmp/wk #コンテナ内のワークディレクトリ command: touch test.txt # コマンド記入・
image:
・・・使いたいイメージを指定する...ではなく作成したdockerfileを指定することもできる。image:
のところをbuild: .
に変更でおk。
・command:
デフォルトのコマンドを上書きしますので要注意。
複数にコマンドを記入したい場合は下記の通り。command: > bash -c "touch test.txt && mkdir output/test && mv test.txt output/test/"はい、できた。
さて、「見本のdocker-conpose.yml」 を動かすと/yourlocal_dir/
の中に test.txt ができます。参考URL:Docker Compose - docker-compose.yml リファレンス
これだけは覚えとけ!docker-composeコマンド
まず、docker-conpose.ymlのあるディレクトリに移動。
cd /yourlocal_dir
起動
イメージがない場合は自動でインストールしてくれます。
今回の場合、瞬殺でtest.txtが出来上がります。
docker-compose up -d
Dockerfileをbuildする場合はこちら。
docker-compose up --build
コンテナの一覧
docker-compose ps
止める
docker-compose stop
再起動
docker-compose restart
logをみる。
docker-compose logs
コンテナの中に入ってみる。
docker-compose exec [コンテナ名] /bin/bash
出るときは[control+C]捨てる
お疲れ様でした。
-f は強制終了。つけない場合は Are you sure? [yN] と聞かれる。
docker-compose rm -f
複数のコンテナの内、1つだけ止めたい!という場合は下記の通り。
下記ルールは他docker-composeコマンドでも使えるようですよ。
docker-compose stop [container_name]
参考URL:docker-compose コマンドまとめ
ちょっと上級者編(筆者的に)
環境変数(.env) について
スマートに書きたい。
バージョンなど変更する場合がある値。
同じ文字打つのめんどい。
という時に!command#テキストエディタで開いて nano .env.env#環境変数を入力して保存 VER=16.04 DIR=/home/peta/ws CMD=touch test_20191107.txtdocker-conpose.ymlはこんな感じ
yaml=docker-conpose.ymlversion: "3" # バージョン services: # 起動するコンテナの定義 ubuntu: image: ubuntu:${VER} # 使いたいイメージをinstall container_name: ubuntu # コンテナの名前 volumes: - ${DIR}:/tmp/wk #hostとマウント working_dir: /tmp/wk #コンテナ内のワークディレクトリ command: ${CMD} # コマンド記入他のPCや仲間に共有したときに、
.env
を変更するだけでいいようにdocker-compose.ymlを書いといたらいいですね。
参考URL:docker-compose.ymlで.envファイルに定義した環境変数を使う別にDockerだけでよくね? という方へ
筆者の個人的感想です。
【利点】
・いろんなコンテナを同時に使える。組み合わせられる。
・docker-compose.ymlへ、コマンドや設定を書いているので、のちのち管理しやすい。
・ymlで書くのでわかりやすい(個人的見解)
→後から見やすいかな?と思いました。
・docker-compose.ymlを渡すだけでまるまる共有できる!!!再現できる!!!(docker-composeコマンド使えたら)【問題点】
・docker-compose.yml 書くのに時間かかりそう。(コンテナの組み合わせを考えたりも)
→時間かかりますが、一度できたら流用しやすそう。【まとめ】
共有・再現する際に非常に役立ちそう。
おわり。
- 投稿日:2019-12-09T13:08:18+09:00
インフラエンジニアがGitLabを建ててCI/CDを動かせるようにするまで
経緯
インフラエンジニアとして入社し、AWS案件に携わってからCloudFormationやLambda用のPythonを書くことが増えました。
Git/GitHub/GitLabの名前は聞いたことがあるレベルでしたが、前述のバージョン管理が必須になり、自社のGitLabを活用することになります。
素人でしたが直ぐに利便性を感じ、自宅にあるESXiにDockerの勉強がてらGitLabを立てればよいのではと考えたのがスタートとなります。
プライベートで自宅のデスクトップPCと外出先で使うノートPCのファイルを扱うのに重宝しています。自宅のESXiに建てている為、それが壊れてしまうと0から構築方法を調べ事になるのを回避したいのでここに忘備録として記載していきます。
Docker
GitLabをDocker-composeで建てたい為、Dockerをインストールします。
※余談ですがk8sをインストールする際にsnapのDockerに苦労したので、下記の方法でDockerをインストールしています。k8sを触らない方はsnapでも問題ないかと思います。環境
項目 値 OS Ubuntu 19.04 ※2019/12月時点でk8sがdockerのver.19に対応していない為、バージョン指定でインストールしています。
sudo addgroup --system docker sudo usermod -aG docker user01 sudo apt-get update sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo apt-key fingerprint 0EBFCD88 sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" sudo apt-get update apt-cache madison docker-ce sudo apt-get install docker-ce=5:18.09.9~3-0~ubuntu-bionic docker-ce-cli=5:18.09.9~3-0~ubuntu-bionic containerd.io sudo systemctl start docker sudo systemctl enable dockerGitLab
Git Labはバージョン管理ツールですが、他にも便利な機能が備わっています。
詳しくは公式サイトをご覧ください。
- Git以外の機能
- CI/CD
- Issues
- Wiki
- etc
GItLab DockerCompose
以下のファイルをダウンロードし、別のPCからもアクセスしたい場合は
GITLAB_HOST=をローカルのIPアドレスへ変更してください。https://github.com/sameersbn/docker-gitlab/blob/master/docker-compose.yml
version: '2' services: redis: restart: always image: sameersbn/redis:4.0.9-2 command: - --loglevel warning volumes: - redis-data:/var/lib/redis:Z postgresql: restart: always image: sameersbn/postgresql:10-2 volumes: - postgresql-data:/var/lib/postgresql:Z environment: - DB_USER=gitlab - DB_PASS=password - DB_NAME=gitlabhq_production - DB_EXTENSION=pg_trgm gitlab: restart: always image: sameersbn/gitlab:12.5.2 depends_on: - redis - postgresql ports: - "10080:80" - "10022:22" volumes: - gitlab-data:/home/git/data:Z environment: - DEBUG=false - DB_ADAPTER=postgresql - DB_HOST=postgresql - DB_PORT=5432 - DB_USER=gitlab - DB_PASS=password - DB_NAME=gitlabhq_production - REDIS_HOST=redis - REDIS_PORT=6379 - TZ=Asia/Kolkata - GITLAB_TIMEZONE=Kolkata - GITLAB_HTTPS=false - SSL_SELF_SIGNED=false - GITLAB_HOST=localhost - GITLAB_PORT=10080 - GITLAB_SSH_PORT=10022 - GITLAB_RELATIVE_URL_ROOT= - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string - GITLAB_ROOT_PASSWORD= - GITLAB_ROOT_EMAIL= - GITLAB_NOTIFY_ON_BROKEN_BUILDS=true - GITLAB_NOTIFY_PUSHER=false - GITLAB_EMAIL=notifications@example.com - GITLAB_EMAIL_REPLY_TO=noreply@example.com - GITLAB_INCOMING_EMAIL_ADDRESS=reply@example.com - GITLAB_BACKUP_SCHEDULE=daily - GITLAB_BACKUP_TIME=01:00 - SMTP_ENABLED=false - SMTP_DOMAIN=www.example.com - SMTP_HOST=smtp.gmail.com - SMTP_PORT=587 - SMTP_USER=mailer@example.com - SMTP_PASS=password - SMTP_STARTTLS=true - SMTP_AUTHENTICATION=login - IMAP_ENABLED=false - IMAP_HOST=imap.gmail.com - IMAP_PORT=993 - IMAP_USER=mailer@example.com - IMAP_PASS=password - IMAP_SSL=true - IMAP_STARTTLS=false - OAUTH_ENABLED=false - OAUTH_AUTO_SIGN_IN_WITH_PROVIDER= - OAUTH_ALLOW_SSO= - OAUTH_BLOCK_AUTO_CREATED_USERS=true - OAUTH_AUTO_LINK_LDAP_USER=false - OAUTH_AUTO_LINK_SAML_USER=false - OAUTH_EXTERNAL_PROVIDERS= - OAUTH_CAS3_LABEL=cas3 - OAUTH_CAS3_SERVER= - OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false - OAUTH_CAS3_LOGIN_URL=/cas/login - OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate - OAUTH_CAS3_LOGOUT_URL=/cas/logout - OAUTH_GOOGLE_API_KEY= - OAUTH_GOOGLE_APP_SECRET= - OAUTH_GOOGLE_RESTRICT_DOMAIN= - OAUTH_FACEBOOK_API_KEY= - OAUTH_FACEBOOK_APP_SECRET= - OAUTH_TWITTER_API_KEY= - OAUTH_TWITTER_APP_SECRET= - OAUTH_GITHUB_API_KEY= - OAUTH_GITHUB_APP_SECRET= - OAUTH_GITHUB_URL= - OAUTH_GITHUB_VERIFY_SSL= - OAUTH_GITLAB_API_KEY= - OAUTH_GITLAB_APP_SECRET= - OAUTH_BITBUCKET_API_KEY= - OAUTH_BITBUCKET_APP_SECRET= - OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL= - OAUTH_SAML_IDP_CERT_FINGERPRINT= - OAUTH_SAML_IDP_SSO_TARGET_URL= - OAUTH_SAML_ISSUER= - OAUTH_SAML_LABEL="Our SAML Provider" - OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient - OAUTH_SAML_GROUPS_ATTRIBUTE= - OAUTH_SAML_EXTERNAL_GROUPS= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_USERNAME= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME= - OAUTH_CROWD_SERVER_URL= - OAUTH_CROWD_APP_NAME= - OAUTH_CROWD_APP_PASSWORD= - OAUTH_AUTH0_CLIENT_ID= - OAUTH_AUTH0_CLIENT_SECRET= - OAUTH_AUTH0_DOMAIN= - OAUTH_AUTH0_SCOPE= - OAUTH_AZURE_API_KEY= - OAUTH_AZURE_API_SECRET= - OAUTH_AZURE_TENANT_ID= volumes: redis-data: postgresql-data:dockerの起動
docker-compose up -dするだけです。
port10080が空いていればアクセスができます。CI/CD
CI/CDを動かすためにはRunnsersの設定が必要です。
RunnsersはRunnerもしくはk8sが必要になります。
今回はRunnserで構築しました。
- GitLabでProjectを作成
- Projectのページに遷移し、左側のSettings
![]()
- CI/CD -> Runners -> Expand
![]()
「Set up a specific Runner manually」に従いセットアップしていきます。
インストール
公式ページsudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64 sudo chmod +x /usr/local/bin/gitlab-runner sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash sudo /usr/local/bin/gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner sudo systemctl enable gitlab-runner sudo systemctl start gitlab-runner
GitLabとの紐づけ
公式ページsudo /usr/local/bin/gitlab-runner register Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com ) # GitLab内のCI/CD SettingsページにあるURLを貼り付け Please enter the gitlab-ci token for this runner # GitLab内のCI/CD Settingsページにあるトークンを貼り付け Please enter the gitlab-ci description for this runner # GitLab内の表示名 Please enter the gitlab-ci tags for this runner (comma separated): # GitLab内のタグ名 Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell: docker #今回はdockerを使用するため、dockerと入力します。 Please enter the Docker image (eg. ruby:2.1): Python:3.7 #今回はpythonを扱う為、python3.7のdocker imageを入力します。CI/CD Settingsページ内のRunners activated for this projectにRunnserが追加されれば成功です。出てこない場合は上記のGitLabとの紐づけを再度実施してみてください。
作成したProjectにCI/CDを設定
- Projectの直下にgitlab-ci.yml を作成
image: python:3-alpine # docker image before_script: # 一番最初に実行するコマンド - pip install pytest pytest-cov autopep8 radon stages: # いくつか実行したいJobの順番を指定できる - build - test job1: # job名(任意) stage: build # stage上のbuildとして設定 script: # listでコマンド記載 - autopep8 -i testCode.py - radon mi -s testCode.py - radon cc -s testCode.py job2: stage: test script: - pytest -v --cov=.上記はjob1が成功したらjob2を実行するようstagesに記載をしています。
gitlab-ci.ymlに関しては以下の記事をご参照ください。もう一つ大事なCDはありませんが、AWS Lambdaの記事を参照頂ければと思います。
まとめ
忘備録として記載した結果、公式のコピペになってしまいました。
GitLabのCI/CDはあまりハマらず設定をすることができました。
これから開発のスピードをポジティブな意味で早くできればと考えています。(インフラエンジニアとは・・・)
公式や先駆者様の見様見真似で動かしている為、おかしな点がありましたらご教示いただけますと幸いです。参考リンク
- 投稿日:2019-12-09T11:44:48+09:00
【Nim】とりあえずにむにむするための環境構築
(ノ)・ω・(ヾ)ニムニム
??遅刻しました??
慌てて急いで書いたNim Advent Calendar 2019の8日目の記事です。
Nimが正式リリースされ、正直なところそれまで聞いたことなかったのですがせっかくなので触ってみたいと思いました。
しかし、環境構築めんどくさいなーと思ってたらDocker Hubに普通にあったのでそれを使ってとにかくNimを書いてみる為の環境を作っていきます。Docker Hub
https://hub.docker.com/r/nimlang/nim用意するもの
- パソコン(大事)
- git
- Docker
- Docker Compose
手順
$ git clone https://github.com/SUGURUHASEGAWA/nimnim.git $ cd nimnim $ docker-compose up -d --build $ docker-compose exec app nimble init はい終わりです。
これでNimプロジェクトと初期コードが生成されるので思う存分にむにむしてください。解説
流石にこれだけではアレなので少しだけ解説していきます。
docker-compose.yml
docker-compose.ymlversion: "3.7" services: app: build: context: ./docker/nim dockerfile: Dockerfile tty: true //常時起動させたい privileged: true volumes: - ./workspace:/opt/${PROJECT_NAME} working_dir: /opt/${PROJECT_NAME}ほぼおまじないレベルの記述です
PROJECT_NAME
は.env
ファイルに定義されているので好きな名前に書き換えてください。Dockerfile
DockerfileFROM nimlang/nim:latest RUN apt-get update && apt-get install -y \ vim \ curl \ mingw-w64これもほぼおまじないですね、
Docker Hubにあるコンテナのlatestバージョンを指定していますが、このVerはお好みで変えてください。
また、mingw-w64
はWindows向けにクロスコンパイルするためにインストールしていますが、今回はとりあえず言語にふれるまでなので割愛します。
まだクロスコンパイルをちゃんとやってないクロスコンパイルについては下記ページを参照するといいかも?
https://nim-lang.org/docs/nimc.htmlnimble init
コンテナを起動したら、コンテナ上で
nimble init
を実行してnimのプロジェクトを作成します。
実行すると対話形式でいくつか質問されるのでお好みで設定してください。(基本的に後からでも編集できます)質問内容
Your name? [Anonymous]
自分の名前を入力。
※未入力の場合はAnonymous
になります。Package type?
Library・・・別アプリケーションに機能を提供するライブラリを作成する場合
Binary・・・エンドユーザ向けのアプリケーションを作成する場合
Hybrid・・・未確認Initial version of package? [0.1.0]
初期Verを設定します
※未入力の場合は0.1.0
Package description? [A new awesome nimble package]
パッケージの説明を入力。Prompt: Package License?
パッケージのライセンスを選択。
MIT等いくつか選択肢が出てくるのでお好みのものをHello, World!
※Package typeでBinaryを選択したものとします
workspace配下のsrcディレクトリ内にあるnimファイルを見てみると以下の様に記述されています
# This is just an example to get you started. A typical binary package # uses this file as the main entry point of the application. when isMainModule: echo("Hello, World!")既にこんにちはしてくれているので、ありがたくこれを使わせてもらいましょう。
※編集する際はこのファイルを基準に記述してくださいプロジェクトにビルドは下記コマンドを実行してください
docker-compose exec app nimble buildコマンドを実行すると、workspace配下にバイナリファイルができているので、実行すると無事こんにちはできます
$ ./nimnim Hello, World!あとがき
Nimの環境構築は正直Dockerを使わなくてもそこまで難しい手順はありませんが、
最近個人的に使用するPCがコロコロ変わるので、いちいちNimをインストールするのが手間だったので、Dockerでの環境構築をしてみました。
(コンテナ持ってきて起動してるだけなので構築と言っていいものか)クロスコンパイルはよく分からなくて手つかずですが、とりあえずNim言語を触って見るぶんにはコスト低く初めれるんじゃないかと思います。
(ノ)・ω・(ヾ)ニムニム
- 投稿日:2019-12-09T09:46:58+09:00
サイボウズOfficeのワークフローをPuppeteerでSlackに通知してみた
はじめに
この記事は 株式会社ピーアールオー(あったらいいな!を作ります) Advent Calendar 2019 の9日目の記事です。
今回は最近困っていることを解決してみようと思います。サイボウズOfficeのワークフローにすぐ気づけない...
サイボウズOfficeでワークフローなどの申請が来た場合、すぐに気づける方法はいくつかあります。
- ブラウザ開いてのホーム画面で確認
- パソコン用リマインダーツールを使う(Cybozu Desktop)
- メールを確認するが、私は基本vscodeとslackばかり見ているので、すぐに気づかずSlackで突っ込まれることが多々あります...
なので、直ぐに気づくことができるよう、ワークフローの申請があった際にSlackに通知するツールを作ってみようと思います。どうやって作る?
サイボウズOfficeのAPIを叩いてワークフローの状況を定期的に参照してSlackに通知しよう!
と、思ったのですが、私が調べた限りではサイボウズOfficeはAPI使えないみたいです。
(kintoneやgaroonはAPI使えるようです。)なので、ヘッドレスでブラウザを操作できるPuppeteerを使って、ワークフローの状況を参照、slackに通知していきたいと思います。
処理の流れ
- dockerでPuppeteer用の環境構築 & 監視用スクリプト稼働
- サイボウズOfficeへアクセスして、ワークフローの状況を取得
- docker(Puppeteer)から、SlackのIncoming Webhookにリクエストを送信
- Incoming Webhook がSlackへ通知
dockerでPuppeteer環境を作る
dockerで開発環境を作っていきます。
まずは、dockerfile。Puppeteer Troubleshootingのdockerのコピペです。FROM node:10-slim # Install latest chrome dev package and fonts to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others) # Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer # installs, work. RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ && apt-get update \ && apt-get install -y google-chrome-unstable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \ --no-install-recommends \ && rm -rf /var/lib/apt/lists/* # If running Docker >= 1.13.0 use docker run's --init arg to reap zombie processes, otherwise # uncomment the following lines to have `dumb-init` as PID 1 # ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 /usr/local/bin/dumb-init # RUN chmod +x /usr/local/bin/dumb-init # ENTRYPOINT ["dumb-init", "--"] # Uncomment to skip the chromium download when installing puppeteer. If you do, # you'll need to launch puppeteer with: # browser.launch({executablePath: 'google-chrome-unstable'}) # ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true # Install puppeteer so it's available in the container. RUN npm i puppeteer \ # Add user so we don't need --no-sandbox. # same layer as npm install to keep re-chowned files from using up several hundred MBs more space && groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ && mkdir -p /home/pptruser/Downloads \ && chown -R pptruser:pptruser /home/pptruser \ && chown -R pptruser:pptruser /node_modules # Run everything after as non-privileged user. USER pptruser # CMD ["google-chrome-unstable"]”次はdocker-compose。
先ほどのdockerfileでコンテナを参照。
ワークフロー監視用のjsを共有後、homeディレクトリにコピーして実行するようにしています。
(共有ディレクトリだと上手く動かなかったので。)参照先のサイボウズの設定なども環境変数に持たせて変更できるようにしました。
参照先はサイボウズOfficeデモサイト。
監視間隔5秒で設定しています。デモサイトなので、パスワードなし。
ログインIDはchromeデベロッパーツールでログインユーザのセレクトボックス(option値)を参照して記載しています。
Basic認証の設定も入れました。処理上は作成しますが、今回はデモサイトで認証がないので適当な値を入れます。version: '3.3' services: puppeteer: build: context: ./ dockerfile: Dockerfile volumes: - ./checkWorkflow.js:/opt/checkWorkflow.js environment: - CYBOZU_URL=https://onlinedemo.cybozu.info/scripts/office10/ag.cgi? - IS_BASIC=0 - BASIC_ID=xxxx - BASIC_PW=xxxx - LOGIN_ID=17 - LOGIN_PW= - SLACK_CHANNEL=@xxxxxxx - SLACK_ENTRY_POINT=/services/xxxxx/xxxxx/xxxxxxxxxxxxxxxxx - LOOP_TIME=5000 command: sh -c "cp /opt/checkWorkflow.js /home/pptruser/. && node /home/pptruser/checkWorkflow.js" tty: true環境変数一覧
環境変数 内容 CYBOZU_URL サイボウズのURL IS_BASIC Basic認証有無(0:なし、1:あり) BASIC_ID Basic認証 ID BASIC_PW Basic認証 Password LOGIN_ID サイボウズログインID LOGIN_PW サイボウズログインPW SLACK_CHANNEL 検知時送信先 Slackチャンネル SLACK_ENTRY_POINT 検知時送信先 Slack送信先URL(パス) LOOP_TIME 監視間隔 開発自体はcommandをコメントアウトして、VSリモートで作成したコンテナにアクセスして開発しました。
Puppeteerで申請状況を取得する
ログイン
docker-composeで設定した環境変数を利用してBasic認証とログインを行います。
「page.select」と「page.type」でログインフォームにログインユーザとパスワードを設定。
「document.querySelector('input[name="Submit"]').click()」でログインボタンを押します。const browser = await puppeteer.launch({ args: ['--no-sandbox'] }); const page = await browser.newPage(); // Basic認証 if (IS_BASIC === '1') await page.authenticate({ username: BASIC_ID, password: BASIC_PW }); // サイボウズアクセス await page.goto(CYBOZU_URL, { waitUntil: 'domcontentloaded' }); // ログイン設定 await page.select('select[name="_ID"]', LOGIN_ID); await page.type('input[name="Password"]', LOGIN_PW); // ログイン await page.evaluate(() => { document.querySelector('input[name="Submit"]').click(); }); // ログイン後画面が読み込まれるまで待機 await page.waitForNavigation({ timeout: 30000, waitUntil: 'domcontentloaded' });ワークフロー取得
ワークフロー画面遷移後、受信一覧を参照します。
最新の申請の番号を取得し、チェック済み配列に格納します。
次回以降は申請済配列を参照し、新規番号がある場合は後続の処理(Slack通知)に繋げるようにしています。// ワークフロー画面へ await page.goto(CYBOZU_URL + 'page=WorkFlowRecept'); // 受信一覧取得 const list = await page.$$('table.dataList > tbody > tr'); // 申請があるか判定判定 if (list.length <= 1) { await browser.close(); console.log("nothing ") return; } // 最新の申請取得 const td = await list[1].$('td') // 申請番号取得 const newAppNumber = (await (await td.getProperty('textContent')).jsonValue()).replace(/\r?\n/g, ''); // ブラウザ終了 await browser.close(); // チェック済みの番号か判定 if (appNumberList.indexOf(newAppNumber) >= 0) { console.log("checked number : " + newAppNumber); return; } else { appNumberList.push(newAppNumber); console.log("new number : " + newAppNumber); }Slackに通知する
SlackのIncoming Webhookを利用して通知します。
Incoming Webhooksについては、以下など、説明されている記事が沢山あると思いますので、割愛します。
参考: SlackのIncoming Webhooksを使い倒す環境変数に設定したSlackのチャンネル、URLを設定してPOSTします。
let postData = { channel: SLACK_CHANNEL, username: 'work-flow-checker', text: '新規申請があります!', icon_emoji: ':ghost:' }; let postDataStr = JSON.stringify(postData); let options = { host: 'hooks.slack.com', // port: 80, path: SLACK_ENTRY_POINT, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postDataStr) } }; let req = http.request(options, res => { console.log('STATUS: ' + res.statusCode); console.log('HEADERS: ' + JSON.stringify(res.headers)); res.setEncoding('utf8'); res.on('data', chunk => { console.log('BODY: ' + chunk); }); }); req.on('error', e => { console.log('problem with request: ' + e.message); }); req.write(postDataStr); req.end();完成
ソースが完成しました。
環境変数を変数に設定後、監視用のfunctionをsetIntervalで定期的に稼働させるようにしています。
チェック済申請番号はメモリ上に保持するので、起動毎にチェック済みの申請番号が消えますが、起動しっぱなしにするので気にしません。ファイル全量. ├── Dockerfile ├── checkWorkflow.js └── docker-compose.ymlcheckWorkflow.jsconst puppeteer = require('puppeteer'); const http = require('https'); // 設定 const CYBOZU_URL = process.env.CYBOZU_URL const IS_BASIC = process.env.IS_BASIC const BASIC_ID = process.env.BASIC_ID const BASIC_PW = process.env.BASIC_PW const LOGIN_ID = process.env.LOGIN_ID const LOGIN_PW = process.env.LOGIN_PW const SLACK_CHANNEL = process.env.SLACK_CHANNEL const SLACK_ENTRY_POINT = process.env.SLACK_ENTRY_POINT const LOOP_TIME = process.env.LOOP_TIME // ミリ秒 // チェック済申請番号格納 var appNumberList = []; async function checkWorkflow() { const browser = await puppeteer.launch({ args: ['--no-sandbox'] }); const page = await browser.newPage(); // Basic認証 if (IS_BASIC === '1') await page.authenticate({ username: BASIC_ID, password: BASIC_PW }); // サイボウズアクセス await page.goto(CYBOZU_URL, { waitUntil: 'domcontentloaded' }); // ログイン設定 await page.select('select[name="_ID"]', LOGIN_ID); await page.type('input[name="Password"]', LOGIN_PW); // ログイン await page.evaluate(() => { document.querySelector('input[name="Submit"]').click(); }); // ログイン後画面が読み込まれるまで待機 await page.waitForNavigation({ timeout: 30000, waitUntil: 'domcontentloaded' }); // ワークフロー画面へ await page.goto(CYBOZU_URL + 'page=WorkFlowRecept'); // 受信一覧取得 const list = await page.$$('table.dataList > tbody > tr'); // 申請があるか判定判定 if (list.length <= 1) { await browser.close(); console.log("nothing ") return; } // 最新の申請取得 const td = await list[1].$('td') // 申請番号取得 const newAppNumber = (await (await td.getProperty('textContent')).jsonValue()).replace(/\r?\n/g, ''); // ブラウザ終了 await browser.close(); // チェック済みの番号か判定 if (appNumberList.indexOf(newAppNumber) >= 0) { console.log("checked number : " + newAppNumber); return; } else { appNumberList.push(newAppNumber); console.log("new number : " + newAppNumber); } // SlackへのPOST用データ作成 let postData = { channel: SLACK_CHANNEL, username: 'work-flow-checker', text: '新規申請があります!', icon_emoji: ':ghost:' }; let postDataStr = JSON.stringify(postData); // POST設定 let options = { host: 'hooks.slack.com', // port: 80, path: SLACK_ENTRY_POINT, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postDataStr) } }; // POST let req = http.request(options, res => { console.log('STATUS: ' + res.statusCode); console.log('HEADERS: ' + JSON.stringify(res.headers)); res.setEncoding('utf8'); res.on('data', chunk => { console.log('BODY: ' + chunk); }); }); req.on('error', e => { console.log('problem with request: ' + e.message); }); req.write(postDataStr); req.end(); }; setInterval(function () { checkWorkflow(); }, LOOP_TIME);動かしてみる
それでは動かしていきます!
デモサイトの申請状況
docker起動
docker-compose up Starting cybozu-puppeteer_puppeteer_1 ... done Attaching to cybozu-puppeteer_puppeteer_1 puppeteer_1 | new number : 11 puppeteer_1 | STATUS: 200 puppeteer_1 | HEADERS: {"content-type":"text/html","transfer-encoding":"chunked","connection":"close","date":"Sun, 08 Dec 2019 21:07:31 GMT","server":"Apache","vary":"Accept-Encoding","strict-transport-security":"max-age=31536000; includeSubDomains; preload","referrer-policy":"no-referrer","x-frame-options":"SAMEORIGIN","access-control-allow-origin":"*","x-via":"haproxy-www-ow8r","x-cache":"Miss from cloudfront","via":"1.1 89e14ce757792ac369341dc84fa01d52.cloudfront.net (CloudFront)","x-amz-cf-pop":"NRT57-C2","x-amz-cf-id":"p0yzt6kUDK3Nk1tuxr7ojy1tWrIgTG8j1F8m2Euu0pIPnxj9kV-gug=="} puppeteer_1 | BODY: ok puppeteer_1 | checked number : 11new numberとして、11番の申請が検知されました。
Slackの方にも通知がきました。デモサイトで追加申請をあげてみます。
新規申請が追加されることで、再度Slackに通知が来るはずです。Slackを確認。追加で申請がきました!
感想
普段サイボウズの通知見逃しが多いので作ってみました。
エラーハンドリングなどあまり考慮せずバッと作ったので、エラー沢山あるかもしれません...
実際に使ってみて、少しずつ直して行く予定です。これで、申請漏れなどなくなることを祈ってます!今回作成したソース
よろしければ使ってみてください。
https://github.com/hiro-kane/cybozu-check-tool参考
- 投稿日:2019-12-09T09:13:35+09:00
Docker 環境に Sftp コンテナを構築して Laravel と連携する
Laravel2 Advent Calendar 2019 - Qiita の 9日目 の記事です。
サンプルリポジトリ
https://github.com/ucan-lab/laravel6-sftp
前準備
まずはLaravelの環境を用意します。
$ git clone git@github.com:ucan-lab/docker-laravel.git laravel6-sftp $ cd laravel6-sftp $ make create-projectできました。
詳しい構築方法は過去記事を参考ください。
- 【忙しい人向け】カップ麺より早く作るDockerでLaravel開発環境構築
- Laravelの開発環境をDockerを使って構築する
- 【初心者向け】20分でLaravel開発環境を爆速構築するDockerハンズオン
Sftpコンテナを作成する
ベースコンテナは atmoz/sftp 使用します。
対向先のディレクトリを作成する
$ mkdir sftp-store $ echo "hello" > sftp-store/world.txt認証用の公開鍵、秘密鍵を作成する
$ mkdir .ssh $ ssh-keygen -t rsa -b 4096 -N "" -f .ssh/ssh_host_rsa_keyGit管理対象外設定をする
.gitignore
/.ssh /sftp-store鍵ファイルやSftp内のデータはGit管理したくないため。
docker-compose.yml
services: app: volumes: - ./.ssh/ssh_host_rsa_key:/root/.ssh/ssh_host_rsa_key sftp-server: image: atmoz/sftp volumes: - ./sftp-store:/home/foo/share - ./.ssh/ssh_host_rsa_key.pub:/home/foo/.ssh/keys/ssh_host_rsa_key.pub command: foo::1001
docker-compose.yml
の差分を抜き出してます。
sftp-server
に公開鍵を配置して、共有ディレクトリ(/home/foo/share
)にローカルディレクリ(./sftp-store
) をマウントします。Sftp コンテナを構築
$ docker-compose down $ docker-compose up -d --buildLaravel で Sftp 設定を行う
$ docker-compose exec app ash
app
コンテナ内で実行します。Sftpライブラリ導入
$ composer require league/flysystem-sftp
SftpServiceProvider を作成する
$ php artisan make:provider SftpServiceProvider
app/Providers/SftpServiceProvider.php
<?php namespace App\Providers; use Illuminate\Support\Facades\Storage; use Illuminate\Support\ServiceProvider; use League\Flysystem\Filesystem; use League\Flysystem\Sftp\SftpAdapter; class SftpServiceProvider extends ServiceProvider { /** * Bootstrap services. * * @return void */ public function boot() { Storage::extend('sftp', function ($app, $config) { return new Filesystem(new SftpAdapter($config)); }); } }Filesystem に sftp 用のアダプタを追加します。
作成した SftpServiceProvider を登録する
config/app.php
'providers' => [ // ... App\Providers\SftpServiceProvider::class, ],Sftp ディスク設定を追加する
config/filesystems.php
'disks' => [ 'sftp-disk' => [ 'driver' => 'sftp', 'host' => 'sftp-server', 'port' => 22, 'username' => 'foo', 'privateKey' => '/root/.ssh/ssh_host_rsa_key', 'root' => 'share', 'timeout' => 10, 'directoryPerm' => 0755, ], ],お試し
$ php artisan tinker >>> Storage::disk('sftp-disk')->get('world.txt'); => "hello\n"差分のコード
参考
- 投稿日:2019-12-09T08:59:37+09:00
Docker を使用するための最初の設定
手元で空いている端末が SD カードの容量が少ない Raspberry Pi 3 B+ (以下 Raspberry Pi)だけだったので、別途 Ubuntu サーバ上に Docker CE をインストールしておき、 Raspberry Pi には docker-ce-cli だけをインストールして、コンテナを作成できるようにします
Ubuntu サーバ上での設定
Ubuntu サーバへは Raspberry Pi から SSH でログインできるように事前に準備しておきます
/etc/systemd/system/docker.service.d/override.conf を作成して、--data-root 等の環境にあった設定をしておきます
docker-ce-cli は Raspberry Pi 上で実行しますが、ここでは -H tcp://0.0.0.0:2375 のように直接外部からアクセスするための -H オプションの指定は不要です
$ cat /etc/systemd/system/docker.service.d/override.conf [Service] ExecStart= ExecStart=/usr/bin/dockerd -H fd:// --data-root /var/lib/docker後は、設定を反映させて docker.service を再起動しておきます
$ systemctl daemon-reload $ systemctl restart docker.serviceRaspberry Pi 上での設定
docker-ce-cli の deb を取得して、インストールします
$ curl -LO https://download.docker.com/linux/raspbian/dists/buster/pool/stable/armhf/docker-ce-cli_19.03.5~3-0~raspbian-buster_armhf.deb $ sudo dpkg -i docker-ce-cli_19.03.5~3-0~raspbian-buster_armhf.debこれで docker-ce-cli は使用できるようになりましたが、Raspberry Pi 上に Docker daemon はいないためこのままでは使用できません
$ docker info Client: Debug Mode: false Server: ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? errors pretty printing infoそのため、docker context でエンドポイントが Ubuntu サーバのコンテキストを作成して、そのコンテキストに切り替えます
$ docker context create --docker "host=ssh://hexa@192.168.1.2" main main Successfully created context "main" $ docker context use main main Current context is now "main"接続してコンテナを作成できるか確認してみます
$ docker container run --rm -it centos:7 bash -c 'cat /etc/redhat-release' CentOS Linux release 7.7.1908 (Core)接続できました
コンテキストは複数作成しておけますし、環境に合わせて簡単に切り替えが可能なため、覚えておくととても便利です
$ docker context use sub sub Current context is now "sub" $ docker context ls dNAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR default Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm main ssh://hexa@192.168.1.2 sub * ssh://ubuntu@192.168.2.2
- 投稿日:2019-12-09T08:45:22+09:00
nginx-proxy と docker-compose でレガシーなLAMP(LEMP)環境を複数稼働できるようにした
この記事は、Makuake Development Team Advent Calendar 2019 7日めの記事です。
yutakiと申します。
PRIME ORDERというWebシステム開発サービスのエンジニアリングマネージャをやっております。
https://prime-order.jp/概要
最近、レガシーな案件のプレビューのために
十数年ずっと頑張ってきたオンプレの共有開発サーバが故障してしまい
急いでnginx-proxyとdocker-composeで複数案件の開発環境を復活させた話をします。やったこと(ざっくり)
※端末はmacです
基本的に下記のコンテナ構成でプロジェクトを作成
- 新しめ(laravel系): [nginx] + [php] + [mysql] + [node(build専用)] の4台構成
- 古め(その他): [apache & php] + [mysql] の2台構成
そしてnginx-proxyでローカルドメインを割り当てました。
たとえばhogeプロジェクトであればhttp://hoge.localhost
で使えるようにした感じです。1. 案件ごとの構成をdocker-composeで作成
ベースimageの選定について
一般的な構成の時は、app以外はほぼ公式イメージで対応しました。
appについては、docker-php-ext-installを使えるので、エクステンションの管理も楽です。
一部、pecl経由でないと入れられないものもありますがそれはpeclで入れて有効にすればいいだけ。
(imagemagickとか)FROM php:7.1-fpm-alpine # lib RUN apk add --no-cache --virtual build-dependencies gcc make autoconf libc-dev libtool \ && apk add --no-cache --virtual zlib1g-dev libxml2-dev \ && apk add --no-cache --virtual libmagickwand-dev libpng-dev imagemagick-dev # composer COPY --from=composer /usr/bin/composer /usr/bin/composer # php extension RUN docker-php-ext-install zip xml pdo_mysql gd RUN pecl install imagick \ && docker-php-ext-enable imagick RUN pecl install mailparse \ && docker-php-ext-enable mailparse COPY php.ini /usr/local/etc/php/ WORKDIR /var/wwwこんな感じで書いたものを使いまわしていけました。
apacheが一緒になっている5.4系のイメージなどはこんな感じ。
FROM php:5.4.45-apache # composer COPY --from=composer /usr/bin/composer /usr/bin/composer # lib RUN apt-get update \ && apt-get install -y git libmagickwand-dev libmcrypt-dev # php extension RUN docker-php-ext-install mcrypt pdo pdo_mysql zip \ && pecl install imagick \ && docker-php-ext-enable imagick # apache module RUN mv /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/ \ && mv /etc/apache2/mods-available/headers.load /etc/apache2/mods-enabled/ # conf, ini COPY site.conf /etc/apache2/sites-enabled/site.conf COPY php.ini /usr/local/etc/php/php.ini WORKDIR /var/www/siteapacheのモジュールがconfファイルを移動するだけで有効になるので楽なのがポイントです。
あとは、ごく少数、PHP5.2みたいな古いバージョンが使われている社内システムもありました。
そちらは公式にはバージョンがないので、DockerHubで該当バージョンを使っているものを探して利用しました。例えば下記など。
https://github.com/andres-ortiz/php5.2-apache2.2
セキュリティパッチ等当ててくれているので開発環境とはいえありがたいです。
ただこのimageは起動時にrun.shでhtdocs以下にログディレクトリを作成してしまうので
スクリプトを上書きするかDocumentrootを変更するなどすると良いと思います。2. nginx-proxy
こちらを利用します。
https://github.com/jwilder/nginx-proxy使い方の要点は下記です。
- どこでもいいのでnginx-proxyをdocker-compose.yml経由で起動しておく
- 各案件のdocker-composeの調整
- 「VIRTUAL_HOST」という環境変数でホスト名を定義する
- nginx-proxyと同じネットワークに所属させる
nginx-proxyを起動しっぱなしにしておけば特に他に設定が不要という神ツールです。
(dockerのプロセスを監視、各docker-composeのup、downを検知して勝手にプロキシしてくれます)nginx-proxy本体のdocker-compose.yml
docker-compose.ymlは最小構成ならこれだけ
docker-compose.ymlversion: '2' services: nginx-proxy: image: jwilder/nginx-proxy ports: - "80:80" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro restart: alwaysちなみにネットワーク名は固定してもいいと思います。
nginx-proxyというディレクトリで起動しているなら「nginx-proxy_default」
がネットワーク名になります。各案件のdocker-compose.yml
たとえばこう
docker-compose.ymlversion: '3' services: hoge-web-php: image: ${WEB_PHP_IMAGE} build: docker/web-php ports: - 80 volumes: - ./logs/apache2:/usr/local/apache2/logs:cached - ./server:/usr/local/apache2/app:cached environment: VIRTUAL_HOST: hoge.localhost hoge-db: image: ${MYSQL_IMAGE} environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DBNAME} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} TZ: ${MYSQL_TZ} command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - ./logs/mysql:/var/log/mysql:cached - ./docker/db/data:/var/lib/mysql:cached - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf - ./docker/db/sql:/docker-entrypoint-initdb.d ports: - 3306 # 下記はnginx-proxyを利用するときのみ解放 networks: default: external: name: nginx-proxy_defaultwebサーバのコンテナのポートは80番にしてください。
あと、サービス名(hoge-web-php, hoge-dbなど)はネットワーク内でuniqueである必要があります。
案件名をprefixなどでつけておくといいと思います。ポイントは、hoge-web-phpの
docker-compose.ymlenvironment: VIRTUAL_HOST=hoge.localostそして最下部の
docker-compose.ymlnetworks: default: external: name: nginx-proxy_defaultです。
なお、このnetworksセクションをコメントアウトしてしまえば通常通りポートフォワードでの利用もできます。
nginx-proxyにproxyさせたいときだけ記述すれば良いです。これで、
http://hoge.localhost
で該当案件を処理することができます。その他
proxyの設定をいじりたい場合
confを上書きすれば簡単です。
こんなふうに上書き
docker-compose.ymlvolumes: - ./proxy.conf:/etc/nginx/proxy.confデフォルトの中身はこうです。
(必要なものは揃っている印象です)proxy.conf# HTTP 1.1 support proxy_http_version 1.1; proxy_buffering off; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; # Mitigate httpoxy attack (see README for details) proxy_set_header Proxy "";SSL対応(リンク紹介だけ)
nginx-proxyをssl対応する場合は
https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion
を活用すれば死ぬほど簡単に対応できます。双方の活用は、素晴らしい参考記事がありましたので貼っておきます
https://tech.quartetcom.co.jp/2017/04/11/multiple-ssl-apps-on-one-docker-host/Laravel Valetを利用する場合
80/443ポートの食い合いになるので使う時は
valet stop
してください。
Laravel Valetはローカルにnginxを立ち上げていて、dnsmasqと併用して似たようなことをしています。valetと共存させようと欲張り、nginx-proxyのポートを
8080:80
にして運用しようとしてみたところ、プロキシはされるのですが
ローカル -> nginxの間のX-Forwarded-*系を伝搬させることができず
Laravelのrouteメソッドなどで適切なURLが作成できませんでした。
しばらく調べてみたんですが、案件ごとにごちゃごちゃ設定するしか手がなさそうだったので断念。これTCPのプロキシならMySQLもいけるんじゃ?->いけなかった
MySQLも
3306:3306
でプロキシしてhoge-db.localhost
でSequel Proとかでアクセスできるんじゃないのか?
と思ってやってみましたが、ホストは解決できるものの正常に通信はできませんでした。
超残念。こちらは大人しくサービスごとにport設定するなどしています。
issueでも似たこと話してました。
https://github.com/jwilder/nginx-proxy/issues/318
- 投稿日:2019-12-09T04:58:25+09:00
【画像で説明】KaggleのNoteBookでpickleをつかい回す
やること
- csvファイルのデータセットをpickle化
- pickleファイルを別のnotebookで読み込む
pickleってなんなのよ?
pythonオブジェクトをバイナリデータで保存するやつ
https://docs.python.org/ja/3/library/pickle.htmlなにがうれしくて?
読み込みが早い
バイナリデータなのでパーズ処理がいらんから早いんですって
学習済みモデルとかもpickle化してつかい回せるこちらの検証記事がすばらしいです
Python: pandas の永続化フォーマットについて調べたタイタニックのデータでやってみる
ひとまずtrain.csvをpickleにする
コードはこれだけ# pickleは標準ライブラリなのでinstall不要 import pickle import pandas as pd train = pd.read_csv('../input/titanic/train.csv') # 'wb'(write binary)を指定 with open('train.pickle', 'wb') as f: pickle.dump(train, f)Datasetとして保存
左上に緑のCompleteがでたらOpen Versionをポチ
train.pickle
が確認できたらNew Dataset
別のnotebookにもってくる
読み込んでみよう
コードはこれだけ
# 'rb'(read binary)を指定 with open('../input/titanicdatasetpickles/train.pickle', 'rb') as f: train = pickle.load(f)train.shape # (891, 12)
ディレクトリ名は画面右に表示されてるものと違うことがあるのでお気をつけください
https://www.kaggle.com/anata-no-namae/data-set-no-namae
<- この表記がディレクトリ名になる!ls ../input # titanicdatasetpicklesファイル化してもよいかも
dumpの処理は使いまわせそう
dump_pickles.pyimport pickle import pandas as pd # Kaggle上と別環境でpathを切り替え if '/kaggle/working' in _dh: input_path = '../input' else: input_path = './input' # コンペごとにココだけ書き換える data_sets = { 'train': f'{input_path}/titanic/train.csv', 'test': f'{input_path}/titanic/test.csv', 'gender_submission': f'{input_path}/titanic/gender_submission.csv' } for name, path in data_sets.items(): df = pd.read_csv(path) with open(f'{name}.pickle', 'wb') as f: pickle.dump(df, f)pandasでも同じことできる
# これは with open('./train.pickle', 'wb') as f: pickle.dump(train, f) # こう train.to_pickle('./train.pickle')# これは with open('../input/titanicdatasetpickles/train.pickle', 'rb') as f: df_ss = pickle.load(f) # こう train = pd.read_pickle('../input/titanicdatasetpickles/train.pickle')こんなエラーでるときある
ModuleNotFoundError: No module named 'pandas.core.internals.managers'; 'pandas.core.internals' is not a package
とか言われたらpandasのバージョンの問題らしい
# Kaggleのnotebookのpandasバージョンとあわせるとよいかも pip install -U pandas==0.25.3で解決
※ Kaggleの公式dockerイメージ(kaggle/python)はpandas==0.23.4でエラーが出たので注意(2019/12/09現在)こちらの記事に救っていただきました
pickleとpandasの不整合おしまい
最後まで読んでいただいてありがとうございました
- 投稿日:2019-12-09T02:05:07+09:00
dockerで立てたMySQLコンテナに外部から接続できずにハマった時の話
概要
dockerを触り始めてMySQLのコンテナを立ててみたものの、Macのターミナルから接続できずに結構ハマった話。似たような事象に陥ってる人が、もしこれで解消できる人がいればと思い記事にしました。
結論
コンテナの3306ポートをEXPOSEしていなかった。docker runで-Pオプションを付けて実行すると上手く接続できた。
before$ docker run -d --name test-db -e MYSQL_ROOT_PASSWORD=password mysql/mysql-serverafter$ docker run -d --name test-db -e MYSQL_ROOT_PASSWORD=password -P --expose=3306 mysql/mysql-server経緯とか
症状
作成したdockerコンテナに対して、Macのターミナルからmysqlコマンドで入ろうとしても、以下の通りエラー
$ mysql -h 127.0.0.1 -u user -p Enter password: ERROR 2003 (HY000): Can't connect to MySQL server on '127.0.0.1' (61)エラー内容的にそもそもIPアドレスがわからないと言われている。
ネットで上手く接続できている人たちの記事を見ると、docker ps時のPORTSに0.0.0.0
があることに気がつく。というわけで、以下の記事を参考にEXPOSEしてみた。EXPOSEする前$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 35b706562745 mysql/mysql-server "/entrypoint.sh mysq…" About an hour ago Up About an hour (healthy) 3306/tcp, 33060/tcp test-dbEXPOSEした後$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 42a9d040091a mysql/mysql-server "/entrypoint.sh mysq…" 14 minutes ago Up 14 minutes (healthy) 0.0.0.0:3306->3306/tcp, 0.0.0.0:32772->33060/tcp test-dbEXPOSE後のPORTS欄を見ると
0.0.0.0:3306->3306/tcp
となっており、ローカルホストから接続できていることがわかる。コピペで適当に作業していると何かあったときにハマりますね...
- 投稿日:2019-12-09T01:50:50+09:00
GCSをマウントしたWeb Server Containerをcreate-with-container でサックリ動かす - Cloud shell で 開発環境要らず
要約
- Chromeのみで
- GCP Console 付属の Cloud Shell を駆使し
- Cloud Storage をマウントした Docker Container を
- gcloud compute instances create-with-container コマンドで
- サックリ簡単にWebサーバを立ち上げます
- Croud Run は gVisor が強力にコンテナ外へのアクセスを制限しているのでgcsfuseが使えないよ
動機
あっ、Webサーバ立てなきゃ、、という時に、IDEやgcloudコマンドやDockerコマンド、その他諸々開発ツールがインストールされたマシンが手元にないケースって割とありますよね。急いでるのに、諸々コマンドやら開発ツールなんか入れてる時間なんて無い…
そんな時でも、ChromeがインストールされたWindows,MAC,iPhone,iPad,Android,Chromebookの何れかがあれば、30分くらいでサックリ目的を達成することができます。手順
Chromeが動くなにかを用意する
スマートフォンでできなくも無いですが、できれば少し大きめな画面とキーボードは欲しいです。
GCPコンソールを起動する
https://console.cloud.google.com/ からGCPコンソールを起動します。
GCPをまだ使ったこと無い、アカウントが無い、という方は、この辺の記事の頭の方を参考にしてGCPコンソールを使えるようにしてください。Google Cloud Shell を起動する
Cloud Shell とは
Google Cloud Shell は、Google Cloud Platform でホストされているリソースを管理するためのシェル環境です。無料で週80時間まで使えます。gcloud コマンドや、go コンパイラ、git, dockerコマンドなど、開発に必要なものは一通り揃ってて便利です。
詳しくはこちら⇒https://cloud.google.com/shell/docs/?hl=ja起動方法
GCPコンソール右上のCloud Shell 起動アイコンをクリックします。
ブラウザ画面下部にShell画面が立ち上がります。Cloud Shell を初期化する
Cloud Shell 環境に、ターゲットのGCP ProjectID を設定します。
gcloud config set project [project id]Google Cloud Strage のバケットを作る
GCS bucketを作ります。
cloud shell内で以下のコマンドを叩いてください。
[bucketname-for-you] の部分は適当な名前を入れてください。名前は全世界で一意で早いものがちです。testとかfoobarとかは誰かがきっととってます。gsutil mb -l asia-northeast1 -b on gs://[bucketname-for-you]エディタを立ち上げる
Cloud Shell 画面右側にある鉛筆アイコンをクリックしてエディタを立ち上げます。
すると、今までダッシュボードが表示されていたブラウザ上部がエディタ画面に切り替わります。Dockerfile他色々書く
エディタ部分の左側ペインにフォルダ構造が表示されています。
適当なフォルダ(ここではwebserverとします)を作り、作ったフォルダのサブフォルダにhtmlフォルダを作ります。
作ったフォルダ直下にDockerfile,php.ini,entrypoint.shを置きます。
htmlフォルダ下にindex.phpを置きます。?webserver ├─?html │ └─?index.php ├─?Dockerfile ├─?php.ini └─?entrypoint.sh今回のコンテナは、以下の構成とします。
- apache
- php7
- gcsfuse
- gosu
DockerfileFROM php:7-apache ENV GCSFUSE_REPO gcsfuse-jessie RUN apt-get update && apt-get install --yes --no-install-recommends \ && apt-get install --yes gnupg \ ca-certificates \ curl \ && echo "deb http://packages.cloud.google.com/apt $GCSFUSE_REPO main" \ | tee /etc/apt/sources.list.d/gcsfuse.list \ && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - \ && apt-get update \ && apt-get install --yes gcsfuse \ && apt-get install --yes gosu \ && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ && mkdir /data COPY php.ini $PHP_INI_DIR COPY ./html /var/www/html COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN chown -R www-data:www-data /var/www/html \ && chown -R www-data:www-data /data \ && chmod a+x /usr/local/bin/entrypoint.sh \ && sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf #EXPOSE 80 443 ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]index.php<?php phpinfo(); ?>php.ini[Date] date.timezone = "Asia/Tokyo" [mbstring] mbstring.internal_encoding = "UTF-8" mbstring.language = "Japanese"gcsfuseは、マウントしたフォルダを使うユーザーで実行しないとフォルダにアクセスできません。ので、gosuでユーザーを指定して実行します。
Dockerfile内でUSER www-data でもマウントできますが、そうするとapacheが80番ポートをListenできなくなります。entrypoint.sh#!/bin/bash gosu www-data gcsfuse $GCS_PATH /data source /etc/apache2/envvars exec apache2 -D FOREGROUNDDockerをビルドし、立ち上げる
Cloud Shell でビルドします。
カレントフォルダを./webserver に移動し、ビルドします。docker build -t web-container .cloud shell内でコンテナを起動します。cloud shell 自体もDocker Container なのですが、その中で更にテストの為にContainerを起動します。
docker run -e PORT=8080 -e GCS_PATH=[bucketname-for-you] \ --device /data --privileged -p 8080:8080 -d \ --name php-web-container web-container結果を見る
エディタ画面右上の枠の中に菱形が描かれたよくわからないアイコンをクリックすると、
ポート8080でプレビュー
というメニューが出てくるので選択します。
新しいタブで動作確認しましょう。Google Container Registory に登録する
駆け足で
docker build -t gcr.io/$(gcloud config get-value project)/web-container . docker push gcr.io/$(gcloud config get-value project)/web-containerインスタンスを作る
gcloud compute instances create-with-container web-container-instance \ --container-image gcr.io/$(gcloud config get-value project)/web-container \ --container-privileged \ --container-env PORT=80,GCS_PATH=[bucketname-for-you] \ --tags http-server \ --zone=asia-northeast1-a \ --scopes=default,storage-fullインスタンスができて80番ポートでListen開始です。
まとめ
これでChromeブラウザさえあれば、いつでもどこでもWebサーバが立てられます。
1コンテナ1プロセスとか、マウントしたGCSバケット使ってないよね、とか、そういった事は適宜調整してくれれば、と思います。
SSL/TLSはCloud Loadbalancerを使いましょう。無料のSSL証明書がいい感じに使えます。
Static なHTMLだけのWebサイトなら、GCSバケットを直接Cloud Loadbalancerから参照すれば、インスタンス分のお金がかからずいい感じです。
- 投稿日:2019-12-09T00:41:30+09:00
.NETCoreのWebAPIをDockerで実行する
はじめに
昔使ってた.NETCoreを使って、WebAPIでDockerを動かしてみたいと思いました。ちなみに私、.NET環境触るの久しぶりだったり、Docker初心者なので、間違ってる〜とか今はこんなのが主流だよ〜とかあったらご指摘いただけると嬉しいです
また、Docker良く分からないけど、なんか動かしてみたい〜っていうMSフレンズも実際にやってもらえたら嬉しいです。
TL;DR
- C#やWindowsServerを使っている方、.NETCoreやDockerを検討している方向けです。
- この記事を読むと、.NETCoreのWebAPIをDockerコンテナで実行できるようになります。
準備
- 環境
- macOS Mojave バージョン 10.14.6
※Windows でも適宜読み替えればできると思います。.NETCoreをインストール
.NETCore SDKからダウンロードします。
バージョンを確認すると...
dotnet --version --version3.1.100
正常に.NETCore SDKのインストールが完了しました。
WebAPIのサンプルプロジェクトを作成
続いて、今回試すAPIのプロジェクトを作成します。
# プロジェクト作成 (my_docker_api は任意のプロジェクト名) dotnet new webapi -o my_docker_api動作確認
# プロジェクトに移動してlocalhost起動 cd my_docker_api/ dotnet runサンプルとして用意されている
WeatherForecast
に
https://localhost:5001/WeatherForecast
でアクセスすると...
Command + C
でlocalhostシャットダウンDockerイメージをビルド
準備
※Dockerをインストール(この記事では割愛)
docker --version Docker version 19.03.5, build 633a0ea
VSCode拡張機能インストール(任意)
Dockerfile作成
Command + Shift + P
でコマンドパレットを開き
Docker: Add Docker Files to Workspace...
を選択
ASP.NET Core
>Linux
を選択すると自動でDockerfile
が作成されます。
Dockerイメージをビルド
my_docker_api_image
は任意のイメージ名でOKです。docker build -t my_docker_api_image -f Dockerfile .
数分かかりますが、最終的に
Successfully
が出ていればOKです。
Dockerイメージの確認
docker images
コンテナーを実行する
docker run --rm -p 5000:80 my_docker_api_image my_docker_api
--rm
: このコンテナー実行後に自動的にコンテナを削除してくれます。不要なコンテナが残り続けるとストレージを圧迫します。
-p 5000:80
: ローカル端末の5000番ポートをDockerコンテナー内の80番ポートに接続します。実行後に
http://localhost:5000/WeatherForecast
にアクセスすると、Docker内のAPIを実行できることを確認できました。先程、
dotnet run
でローカル実行したときと同様のことがDockerコンテナで実行できることが分かります。感想
これだけではDockerの旨味は感じられにくいが、Dockerで開発することができれば、そのままAWS ECS/Fargateを使ってデプロイできるみたい。(でも今は、.NETCore2系まで対応で3系はまだかな?) マイクロサービスやサーバーレスアプリケーションを作成するなら使いたい技術だと感じました。
〜後日談〜
Dockerには様々な使い方があります。例えば、開発環境をメンバー全員で揃えたいとか、サービス運用を楽にしたいとか。つまり、解決したい課題を明確にして自分がどのようにDockerを使いたいか把握することが大事なんだと気づきました。参考にした記事
- Docker で ASP.NET Core ウェブアプリケーションを動かす @Nossa さん
- チュートリアル: NET Core アプリのコンテナー化
- チュートリアル: ASP.NET Core で Web API を作成する
私たちのチームで働きませんか?
エイチームは、インターネットを使った多様な技術を駆使し、幅広いビジネスの領域に挑戦し続ける名古屋の総合IT企業です。
そのグループ会社である株式会社エイチームブライズでは、一緒に働く仲間を募集しています!上記求人をご覧いただき、少しでも興味を持っていただけた方は、まずはチャットでざっくばらんに話をしましょう。
技術的な話だけでなく、私たちが大切にしていることや、お任せしたいお仕事についてなどを詳しくお伝えいたします!Qiita Jobsよりメッセージお待ちしております!
- 投稿日:2019-12-09T00:34:14+09:00
OS別、DockerクライアントのみをインストールしてリモートのDockerに接続する為の設定方法
DockerデーモンにTLS接続出来るのが前提の記事となっています。
検証環境
- Windows 10 Pro version 1909
- Ubuntu 19.04
- macOS Catalina
共通の手順
クライアントのインストール手順はOS毎に違いますが、接続先の設定は認証用のファイルを~/.dockerに置いて環境変数を設定するだけです。
公式手順に従っていた場合はca.pem,cert.pem,key.pemの3つのファイルが出来ているはずなので、この3つのファイルを各クライアントにコピーし、~/.dockerに移動しておきます。
デフォルトの接続先をUNIXソケットからTCPソケットに変えるには下記の2つの環境変数を設定します。
DOCKER_HOST=tcp://hoge.exampl.com:2376 DOCKER_TLS_VERIFY=1上記の
hoge.exampl.com:2376
は接続先のFQDNとポートに置き換えてください。Docker Clientのインストール (Ubuntu)
公式手順の最後の
sudo apt-get install docker-ce docker-ce-cli containerd.io
のところでdocker-ceとcontainerd.ioを省くだけです。Docker Clientのインストール (macOS)
Homebrewがdockerを配布しているので、これを利用するのが簡単です。多分クライアントだけだと思います。
brew install dockerDocker Clientのインストール (Windows)
Windowsでは決定版的パッケージマネージャーが存在せず、少なくともMSYS2のpacman等ではdockerの配布はされていません。
取れる手段は3つです。
- WSLにインストールして、Windows側にwsl上のdockerを呼び出すラッパーを用意する。
- 公式配布の古いバイナリをダウンロードし、パスを通す。
- 自分で公式ソースをビルドし、パスを通す。
1番はお手軽ではあるものの、VSCodeのRemote - Containersが使う
||
の解釈に失敗して上手く動きませんでした。2番もお手軽ではあるものの、VSCodeのRemote - Containersが未実装のオプションを利用する為上手く動きませんでした。
よってここでは3番で行きます。
Docker Clientをビルドする
gitコマンドが使える、dockerがインストールされている環境で作業します。
dockerはクロスビルドに対応している為、Windowsでなくて構いません。適当なディレクトリを作り、そこにdocker-ceのリポジトリをcloneします。
$ mkdir ~/docker-ce $ cd ~/docker-ce $ git clone https://github.com/docker/docker-ce.git .これで取得するソースは開発版になるので、安定版が良い場合はバージョンをタグで指定してcheckoutします。
v19.03.5への切り替え$ git checkout refs/tags/v19.03.5次にDocker Clientのディレクトリに移動し、ビルドを行います。
$ cd components/cli/ $ make -f docker.Makefile binary-windowsmakeにdockerコマンドを利用している為、dockerコマンドにsudoが必要な環境ではmakeの前にsudoをつけてください。
ビルドが完了するとbuildフォルダの中にdocker-windows-amd64というファイルが出来ているので、これをWindowsの適当なディレクトリにscp等でコピーします。
コピーしたファイルをdocker.exeにリネームし、環境変数のPATHにdocker.exeのあるディレクトリへの絶対パスを追記すればインストール完了です。
参考文献
- 投稿日:2019-12-09T00:33:32+09:00
Ubuntu 19.04でDockerデーモンにTLSで接続できるようにする
対象とする環境
Dockerのインストールが済んでいる、Ubuntu 19.04を想定しています。
Ubuntu 18.04 LTS以降であれば、systemdを使っているので同じ手順で大丈夫だとは思います。
手順
公式ドキュメントに沿って進めます。
実行にroot権限が必要なコマンドは文頭に#を、そうでなければ\$をつけています。
複数のファイルを生成するので、適当なディレクトリを作成して移動しておきます。
ここではホームディレクトリにdocker-authというディレクトリを作ることにします。$ mkdir ~/docker-auth && cd ~/docker-auth自己署名用の秘密鍵を作成する
$ openssl genrsa -aes256 -out ca-key.pem 4096パスフレーズを求められます。このパスフレーズはDockerのTLS接続時に使うものではないので、長くて複雑なものを用いて構いません。
自己署名用の証明書要求を作成する
$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pemdaysで設定する整数値は証明書要求ファイルの有効日数です。ここでは1年間にしています。必要に応じて調整してください。
パスフレーズの入力を求められるので、先ほど秘密鍵で設定したパスフレーズを入力してください。
その後所在地の入力等を求められるので適当に入力します。Common NameにはDockerソケットの公開元であるサーバーのFQDNを入れてください。
サーバー用の秘密鍵を作成する
$ openssl genrsa -out server-key.pem 4096サーバー側の処理であり、パスフレーズの入力ができない為、こちらはパスフレーズを設定しません。
サーバー用の証明書要求を作成する
$ openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr\$HOSTはサーバーのFQDNと置き換えてください。
サーバー用の自己署名証明書を作成する
$ echo subjectAltName = DNS:$HOST,IP:$HOST_IP,IP:127.0.0.1 >> extfile.cnf $ echo extendedKeyUsage = serverAuth >> extfile.cnf $ openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \ -CAcreateserial -out server-cert.pem -extfile extfile.cnf\$HOSTはこちらでもサーバーのFQDNと置き換えます。
\$HOST_IPはサーバーへの接続に使うIPアドレスを設定します。自分はサーバーを自宅に置いている為、LAN内からでも接続できるようにプライベートIPを指定しました。
こちらも有効期間は1年間としています。必要に応じて調整してください。
パスフレーズには最初に設定したものを入力してください。
クライアント用の秘密鍵を作成する
$ openssl genrsa -out key.pem 4096こちらも利便性の為にパスフレーズを設定しません。
クライアント用の自己署名証明書を作成する
$ echo extendedKeyUsage = clientAuth > extfile-client.cnf $ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \ -CAcreateserial -out cert.pem -extfile extfile-client.cnfこちらも有効期間は1年間としています。必要に応じて調整してください。
パスフレーズには最初に設定したものを入力してください。
不要なファイルを削除し、権限を設定する。
$ rm -v client.csr server.csr extfile.cnf extfile-client.cnf $ chmod -v 0400 ca-key.pem key.pem server-key.pem $ chmod -v 0444 ca.pem server-cert.pem cert.pem証明書要求ファイルと拡張設定ファイルは証明書の作成が済めば不要なのでここで削除しておきます。
残ったファイルはどれも大切に保管する必要があるので、適切な権限を設定しておきます。
DockerデーモンへのTLS接続を許可する
# mkdir /etc/docker/auth-files # cp {ca,server-cert,server-key}.pem /etc/docker/auth-filesDockerデーモンが用いる証明書要求、サーバー用自己署名証明書、サーバー用秘密鍵を適当な位置に移動しておきます。
Ubuntu19.04ではデーモンの起動にsystemdを用いているため、/lib/systemd/system/docker.serviceにある設定ファイルを編集します。
docker.service~省略~ [Service] ~省略~ ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/etc/docker/auth/ca.pem --tlscert=/etc/docker/auth/server-cert.pem --tlskey=/etc/docker/auth/server-key.pem -H tcp://0.0.0.0:2376 -H fd:// --containerd=/run/containerd/containerd.sock ~省略~dockerdの起動オプションに
--tlsverify --tlscacert=/etc/docker/auth/ca.pem --tlscert=/etc/docker/auth/server-cert.pem --tlskey=/etc/docker/auth/server-key.pem -H tcp://0.0.0.0:2376
を追記しました。ここで指定するTLS接続の為の設定はあくまでtcp接続の際に用いるものなので、
-H fd://
を残しておくことでサーバー上ではこれまで通りUNIXソケットを経由してdockerコマンドを使うことができます。あとはDockerデーモンを再起動すればTLS接続が有効になっています。
ufw等を使っている場合は適宜ポート開放を行い、クライアントからdockerコマンドで接続出来ることを確認してください。
OS別のDockerクライアントインストール方法は別記事にて取り扱います。
参考文献
- 投稿日:2019-12-09T00:30:27+09:00
VSCodeとリモートDockerを利用した、シンクライアントな開発環境の構築
この記事はSFC-RG Advent Calendar 2019の11日目です。
Docker使っていますか?
Docker便利ですよね。仮想環境より遥かに低コストで、プロジェクト単位で開発環境を用意できるので、ホスト環境が次第に汚れていく不快感から永遠にオサラバすることができます。
一方、DockerデーモンはLinuxでしか動かない為、macやWindowsでDockerを使う場合はDockerデーモンを動かす為に仮想環境が必要となり、意外とリソースを消費してしまいます。
Visual Studio Code(以降VSCode)では、拡張機能の一つであるRemote Developmentを使うことで、コンテナを開発環境として利用することが可能です。
これにはdockerコマンドを用いているため、Docker Remote APIを使ってリモートのコンテナも開発環境として利用することが出来ます。
Dockerをサーバーで動かす
- メリット
- 非力なノートパソコンでもDockerを快適に利用可能
- クライアントが変わっても作業を継続可能
- 自宅で暇しているサーバーに仕事を与えられる
話題のシンクライアント- デメリット
- 最初の準備がやや大変
- オフラインでは作業不可
- 自宅にサーバーが無い場合は別途用意する必要がある
検証に用いた環境
- サーバー
- Ubuntu 19.04
- Docker Engine - Community version 19.03.4
- クライアント
- Windows 10 Pro version 1909
- Docker Client version 19.09.0-dev (自分でソースからビルド)
- macOS Catalina version 10.15.1
他ソフトウェア、拡張機能は2019年12月時点での最新安定板を利用
必要なもの
サーバー側
- Docker
クライアント側
- Docker client
- Visual Studio Code
サーバーでの準備
サーバーでDockerデーモンを動かし、これをDocker Remote APIでクライアントから扱うには、Dockerデーモンのソケットをネットワークに露出させる必要があります。
Dockerデーモンへのアクセス権はroot権限を意味する為、セキュリティの観点からTLSを用いた認証、暗号化が必須です。
別記事を用意したのでそちらに従うか、公式ドキュメントを参考にDockerデーモンにTLSを使ったTCP接続が出来るようにしてください。
クライアントでの準備
dockerコマンドのインストールと設定
クライアントにはDockerデーモンを入れる必要はありませんが、Dockerクライアントはインストールし、接続先を指定する必要があります。
UbuntuやmacOSではパッケージマネージャーを用いてDockerクライアントのみのインストールが可能です。
Windowsの場合は公式からの安定版のバイナリ配布が17.09.0で止まっており、これはVSCodeでは動かない為、自分で公式ソースからバイナリをビルドして適当な場所に配置し、パスを通す必要があります。
詳細手順はこちらも別記事を用意したのでこちらに従ってください。
Visual Studio Codeのインストールと設定
リモートコンテナへの接続はVSCode公式でも言及がなされています。
VSCodeをインストールした後、Remote Development拡張機能を追加します。
また、Docker拡張機能も、リモートのコンテナを直接管理出来て便利なので追加します。Docker拡張機能はそれ自体がDocker Remote APIを利用するため、VSCodeの設定ファイルに下記1行を追記してください。
settings.json{ "~省略~", "docker.certPath": "~Dockerデーモンへの接続に必要な認証ファイルを置いたディレクトリへの絶対パス~" }VSCodeのDockerタブからリモートのコンテナやイメージ等が見れるようになれば準備完了です。
使用例
以降クライアントでVSCodeのみを操作します。サーバーでの操作は一切必要ありません。
作業ディレクトリを開く
適当な場所に作業ディレクトリを作って開きます。ディレクトリ名はDockerイメージ名に使われるので、プロジェクト名にでもしておくと便利です。
開発コンテナ設定ファイルを作る
VSCodeではdevcontainer.jsonという独自のファイルで開発環境とするコンテナの設定を記述します。
公式で既に非常に多くのテンプレートが用意されているので、これにリモート用の設定を追記するのが簡単です。
ウィンドウ左下の緑のボタンから
Remote-Containers: Add Development Container Configuration Files...
を選ぶことでdevcontainer.jsonが生成されるので、これに下記2行を追記します。devcontainer.json{ "~省略~", "workspaceMount": "src=remote-workspace,dst=/workspace,type=volume,volume-driver=local", "workspaceFolder": "/workspace" }上記の設定文中の
remote-workspace
はプロジェクトファイルを保存することになるボリューム名ですので、プロジェクト名に置き換えるなど、一意性を保てるように適宜変更してください。コンテナは永続性の必要なデータを置く場所ではない1ので、上記設定を追加することでボリュームに保存するようにします。
勿論ボリュームも通常のディレクトリと同じく、絶対的な永続性を保証する機能ではない事には注意してください。
開発コンテナに接続する
設定ファイルが用意出来たら後は接続するだけです。
ウィンドウ左下の緑のボタンから
Remote-Containers: Reopen in Container
を選べば、VSCodeが設定ファイルを元にコンテナの作成、実行、接続を自動で行ってくれます。初回実行時はイメージのビルドも行うため暫く時間がかかりますが、2回目以降はより高速に接続が完了します。
接続後はローカルでの開発と変わらない使い勝手でリモート上にプロジェクトファイルを展開していくことができます。
他のクライアントから接続する
設定ファイルのある作業ディレクトリを丸ごとコピーしてきて、
Remote-Containers: Open Folder in Container...
を実行するだけです。参考文献
DockerデーモンへTCP接続をする方法
Protect the Docker daemon socket
VSCodeからリモートのコンテナを利用する方法
Developing inside a container on a remote Docker host
- 投稿日:2019-12-09T00:00:50+09:00
オレオレ開発環境2017〜2019年版
この記事はひとり開発 アドベントカレンダー 2019年の8日目の記事です。
開発環境の紹介 (VM->Docker with tmux, vim)と題して、ここ3年に渡る私のターミナル周りの開発環境の推移をまとめていく記事です。2017年 dotfiles + git
dotfilesとはなんぞやについては今年のアドベントカレンダー1発目に詳しく書かれているので参照してみてください。
ようこそdotfilesの世界へインストール方法
$ bash -c "$(curl -fsSL git.io/dotu1)"ワンコマンドでインストールできます。ただし、インストール時に表示される注意書きにもあるように、インストール先のホームディレクトリ上のファイルを上書きするので、上書きされたくないファイルがあったら予めリネームするなどして退避してください。あくまで自分用にしか作っていないので、インストールするときはファイルを上書きするし、アンインストール方法は用意されていません。ファイルが損失しても責任を取りかねます。
ジョブ内容
- dotfilesをクローンしてファイルを上書きします。
- bacpacを使ってArchlinuxで使っていたのパッケージをインストールします。
- pyenvを使用してpython 環境を構築します -> 今はdockerでpython環境を構築しているので基本的に使いません。
- デフォルトのshellをzshに変更します。
bacpac
元はこれAUR - bacpac
フォークしたのが自分のGist Gist - u1and0/.bacpac.md Secretパッケージマネージャにpacmanを使っているOSなら使えます。
インストールしたパッケージをgitで管理するshell script。古いのかもしれないです。
元のソースと比べてbacpac cat
,bacpac diff
のサブコマンドと、zshの補完機能_bacpac
を追加しています。submoduleで管理しています。
.gitmodules[submodule "bacpac"] path = bacpac url = https://gist.github.com/u1and0/8bd32ade8d95988b52b03a1b08297b96 ignore = dirty # dotfilesには関係ないパッケージの追加・削除による差分を感知しないzsh
- .bash_aliases
- .bash_functions
- .bashrc
- .zsh_aliases
- .zsh_functions
- .zsh_keybinds
- .zshrc
- .zplug.zsh
この辺で管理しています。
.zshrc呼び出すときに.bashrc
をsourceしているので、bashの設定をオーバーライドしています。.zshrcif [ -f ~/.bashrc ]; then . ~/.bashrc fi if [ -f ~/.zsh_aliases ]; then . ~/.zsh_aliases fi if [ -f ~/.zsh_functions ]; then . ~/.zsh_functions fizplug
zplugはzshに入れるプラグインマネージャです。
以下の設定を.zshrcに書いておくことでzplugをgithubからクローンしてzplug及びzplugで管理されるプラグインをインストールしてくれます。.zshrc# 2回目以降は.zplug/init.zshを読み込んでロード if [[ -f ${HOME}/.zplug/init.zsh ]]; then export ZPLUG_LOADFILE=${HOME}/.zplug.zsh source ~/.zplug/init.zsh # Auto installer if ! zplug check --verbose; then printf "Install? [y/N]: " if read -q; then echo; zplug install fi fi # コマンドをリンクして、PATH に追加し、プラグインを読み込む zplug load # 初回はzplugをcurlでインストール else; printf "Install zplug? [y/N]: " if read -q; then curl -sL --proto-redir -all, https\ https://raw.githubusercontent.com/zplug/installer/master/installer.zsh | zsh && source $0 # .zshrc再リロード fi fitmux
- .tmux.conf
- .tmux/plugins/tpm
この辺で管理しています。
submoduleも入れています。.gitmodules[submodule ".tmux/plugins/tpm"] path = .tmux/plugins/tpm url = https://github.com/tmux-plugins/tpm主な使い方
- セッション切り替え
- C-Space J
- C-Space K
- セッションデタッチ
- C-Space d
- ウィンドウの新規作成
- C-Space c
- ウィンドウの削除
- C-Space x
- ウィンドウ切り替え
- C-Space L
- C-Space H
- ペイン切り替え
- C-Space j
- C-Space k
- C-Space l
- C-Space h
- ペインの新規作成(横分割)
- C-Space "
- ペインの新規作成(縦分割)
- C-Space %
- コピー(ヤンク)
- C-Space SpaceでコピーモードにはいってからSpaceと移動キーで選択してy
- ペースト
- C-Space p
nvim
エディタはneovimです。
dotfilesでは以下のファイルで管理しています。
プラグインマネージャはShougo/dein.vim
- .config/nvim/init.vim: neovimが呼び出されるときに
source
する。これが親- .config/nvim/keymap.rc.vim :neovimのキーバインド
- .config/nvim/options.rc.vim: neovimのオプション
set
で設定するもの- .config/nvim/autocmd.rc.vim:
autocmd
で設定するもの- .config/nvim/ftplugin/arduino.vim: arduino使うときに入れてたけど今使ってない
- .config/nvim/ftplugin/html.vim: htmlファイル開いたときのタブ設定など
- .config/nvim/ftplugin/javascript.vim: jsファイル開いたときのタブ設定など
- .config/dein/plugins.toml: 常に呼び出されるdein管理のプラグイン
- .config/dein/lazy.toml: 特定の条件下で呼び出されるdein管理のプラグイン
- .config/dein/lightline.toml: UIかっこよくする
- .config/dein/vim-airline.toml: UIかっこよくする。今は使っていない
- .config/dein/python.toml: python3+としてコンパイルされているneovimでないと使えないプラグイン
python環境
python環境を使い分ける〜pyenvとcondaのメモ〜
pyenv+condaを使ってpython環境の構築をする記事です。
2018年 vagrant + Virtual Box
Archlinux on Vagrant 日本語/GUI/docker セットアップスクリプト
この辺からドットファイルとパッケージだけではなくinfrastructure as code, 環境周りを一括して管理するようになりました。
これまでWindows機でCmder上でやっていたところ、watchコマンドが使えなかったりで本格的なLinuxを使いたいと思い、Windows10上にvagrant+VirtualBoxを使ってオレオレArchlinuxイメージを作って色々いじっていました。
Linuxマシンになってなるべく困難は調べものして解決するつもりでしたが、どうしてもうまく行かなくなったときは仮想マシンのスナップショット機能で過去に戻ればいいし、最悪新しい環境をもう一つ作ればいいやという軽い気持ちで使い始めました。2019年 docker
この辺からWindows10を捨ててUbuntu18.04に移行しました。
VirtualBoxではパフォーマンス面でリソースを100%活かしきれていないことが気になったので、CPUやメモリをホストと共有できるコンテナ仮想環境dockerに開発環境を移行しました。ポータブルなので、一度イメージ構築してしまえば新しいマシンに移ってもイメージをpullするだけなので、引っ越しに抵抗がありませんね。
オレオレdocker開発環境を作ってみたにも自分用docker環境構築を書きました。
この記事ではさらにその続きで、docker-composeを使って各dockerコンテナをワンコマンドで立ち上げようという試みです。docker-compose.yml# maintainer: u1and0 <e01.ando60@gmail.com> # version 3.7 for docker version 18.06+ # see https://docs.docker.com/compose/compose-file/ # What for: # docker in docker dev.env # master: zsh & zplug env. Pairents for all docker image. # python: python env. It can use ipython & jupyter # # Usage: # $ cd /path/to/composeset # $ docker-compose start master # Starting master ... done # Starting jupyter ... done # Starting vimgo ... done # $ docker exec -it composeset_master_1 zsh -l # version: '3' services: master: image: "u1and0/myenv:latest" tty: "true" volumes: - "${HOME}:/home/vagrant" - "${HOME}/.zsh_history:/root/.zsh_history" - "${HOME}/yankring_history_v2.txt:/root/yankring_history_v2.txt" - "/mnt/e/Users/U1and0:/mnt" - "/var/run/docker.sock:/var/run/docker.sock" working_dir: "/home/vagrant" environment: - "HOST=master" command: "zsh" jupyter: # jupyter tagはpasswordを設定したイメージ # [Jupyter on Dockerでパスワードの設定方法が分からないあなたへ](https://qiita.com/Yusuke-Shimizu/items/731ca71b3c4c3649ec7f) image: "u1and0/pyenv:jupyter" volumes: - "${HOME}:/home/vagrant" - "/mnt/e/Users/U1and0:/mnt" working_dir: "/home/vagrant/Dropbox/Program/python" environment: - "PYTHONPATH=/home/vagrant/Dropbox/Program/python" command: "bash -c 'source /root/.pyenvrc && source activate && jupyter notebook --allow-root'" ports: - "8888:8888" vimgo: image: "u1and0/vim-go:zplug1.2.0-r1" tty: "true" working_dir: "/root/go/src" volumes: - "${HOME}:/home/vagrant" - "${HOME}/.zsh_history:/root/.zsh_history" - "${HOME}/yankring_history_v2.txt:/root/yankring_history_v2.txt" - "/mnt/e/Users/U1and0:/mnt" environment: - "GO111MODULE=on" - "HOST=go" ports: - "8080:8080" cap_add: - "SYS_PTRACE" # for golang debuggerdotfilesでは .docker/config.json でC-/ C-PからC-\ C-/にデタッチキーを変更しています。
docker/config.json{ "detachKeys": "ctrl-\\,/" }
イメージ名 使用用途 image: "u1and0/myenv:latest" DinD image: "u1and0/pyenv:jupyter" Python環境 image: "u1and0/vim-go:zplug1.2.0-r1" Go環境 使い方
$ cd /path/to/composeset # 1 $ docker-compose start master # 2 Starting master ... done Starting jupyter ... done Starting vimgo ... done $ docker exec -it composeset_master_1 zsh -l # 3
- docker-compose.ymlがある場所で
docker-compose start
するだけで、docker-compose.ymlに記載している全環境をワンコマンドで立ち上げます。 ハマりどころとしては、DinDをするためにホストマシンの/var/run/docker.sock
をボリュームにマウントすること。そして、tty:true
としておかないとcommand
がzshなどのshellを指定しているimageが一瞬で落ちてしまうことです。docker exec ...
で各環境にattachします。 とりあえずDinD(Docker in Docker)用のimage: masterにいつもログインして、tmuxを起動し、作業に入ります。Goで開発するなら
$ docker exec -it composeset_vimgo_1 zsh -lPythonで開発するなら
$ docker exec -it composeset_jupyter_1 bash -c "source ~/.pyenvrc && source activate && ipython" $ docker exec -it composeset_jupyter_1 bash -c "source ~/.pyenvrc && source activate && nvim +PyenvActivate"commandにjupyter notebookを指定しているので
localhost:8888
をブラウザのURL欄に打てばJupyter Notebookに接続できます。
Pythonパッケージマネジャにpyenv+condaを使っているのでログイン時必ずsource activate
しないといけません。
source activate
するためのパスが通っていないためにsource ~/.pyenvrc
しないといけません。
.pyenvrcは自分で書いたものです。.pyenvrc#!/bin/sh # pyenv config file # pyenvのあるpath export PYENV_ROOT="$HOME/pyenv" export PATH="$PYENV_ROOT/bin:$PATH" # pyenv実行 eval "$(pyenv init -)" # bin/activate bin/deactivateを使うため PATH="$PYENV_ROOT/versions/miniconda3-latest/bin:$PATH" PATH="/usr/bin:$PATH" export PATH PYTHONPATH="${HOME}/Dropbox/Program/python/:$PYTHONPATH" PYTHONPATH="${HOME}/home/python/:$PYTHONPATH" export PYTHONPATHこのへんまだまだベストな状態ではありません。Dockerでパッケージ管理するなら、condaなんて使わずにpipだけでいいのでわー?condaが依存パッケージ集めてくれるから楽なのか?今は「今までcondaで管理してきたから」という理由だけでcondaを使い続けています。
その他の開発するなら
masterイメージでshell scriptとかやったりします。qiita記事もこのイメージ内のneovimで作成しています。
2020年以降は
またVT-x系仮想環境に戻ろうと思います。
その上でDocker立ち上げようかと。
なぜなら、ホストマシンの電源を切ると開発の流れが途切れるからです。
常用ではホストマシンは就寝前にスリープモードにするのですが、ホストマシンのアップデートとかはいったりなんか調子おかしくなったときはリブートせざるを得ないときが必ずあります。上で説明したdotfilesにはターミナルの復元ツールが多数含まれています。
- すべてのファイルはDropboxに保存して、万一ロールバックしたいときでも簡単に復元できる。
- そもそもgitが使えばコードの差分を見ながら過去に戻れたり別バージョンを残しておいたりできる。
- tmux-plugins/tmux-resurrectでtmuxのセッションを復元できる。Space C-rに割り当てています。
- tpope/vim-obsessionでneovim/vimのセッションを復元できる。立ち上げるときに
nvim -S
というSオプションをつける。- docker-composeもdocker-compose.ymlのディレクトリに飛んで
docker-compose start
するだけでコンテナ郡は一発復元する。このように復元方法には困らないのですが、しかしながら一回途切れるものは途切れる。そのへんやっぱり仮想マシン用意してセッションを保存しておけばホストの電源落としてもかならずセッション復元するし、スナップショットも取れる。そしてDockerに移住したもののそんなにリソースを食う処理って滅多にやらない。
そんなわけでまたVirtualBoxかなんかに戻ろうと思います。
今注目しているのがkvmとmultipass。
multipassはこの記事「仮想環境multipassを試す」で少しいじってみた。VirtualBoxでやったところで、結局CUI環境はDockerで構築するわけなので、間に挟むイメージはなんでもいい、ということで安直にUbuntu一択になってしまうわけです。multipassは選べるイメージがUbuntuのみでシンプルに作られているので気に入りました。
しかしながら、ポートフォワーディングが今のところできないみたいなので、サーバー・ブラウザ・web使う系の開発に使えないのでまだ様子見です。
kvmはインストールがうまくいかないので、試行錯誤中です。
時間かかるようだったらvagrant+VirtualBoxで良いかなと思います。慣れているし。まとめ
開発環境構築は永遠に終わらない開発の一つです。僕のdotfilesは一人でコミット数が719件になりました。
今後も快適な開発のための開発環境作りに勤しんで参りたいと思います。
今年もアドベントカレンダーに多くのCUIツールが紹介されていたので、試したくてウズウズしているところです。