- 投稿日:2019-08-16T22:11:04+09:00
Dockerで使うコマンドのメモ
こんにちは、未来電子のインターンでプログラミングを勉強している者です。
今週はDockerについて少し学んだので、Dockerで使われるコマンドをメモします。Dockerとは
Dockerとは、Docker社が提供している仮想化技術のことです。
Dockerでは、コンテナと呼ばれる仮想環境の中でアプリケーションを操作できます。
コンテナは、ホストマシンのカーネルを共有しており、複数のコンテナを一つのホスト上で同時に動かすことができます。
そのため、Dockerは、ハイパーバイザの上に別々のゲストマシンを置くVirtualBoxとは違い、動作が軽いことが特徴です。Dockerで使われるコマンド
Dockerでは、コマンドを用いてイメージ(コンテナを操作するための設定をまとめたもの)やコンテナの操作をします。
ここでは、主に用いられるコマンドを挙げていきます(親コマンドのdockerは省略)。
コマンド 意味 login レジストリにログインする logout レジストリからログアウトする pull イメージやリポジトリをレジストリから取得する push イメージやリポジトリをレジストリに追加する images イメージを一覧表示する build Dockerfileからイメージをビルド(ベースイメージに機能を付け加える)する tag イメージにタグをつける create 新規のコンテナを作る run 新しいコンテナを起動する attach 起動しているコンテナを操作する start コンテナを起動する stop コンテナを停止する rm コンテナを削除する ps コンテナを一覧表示する まとめ
今回は、Dockerで主に使われるコマンドをまとめてみました。
他にもコマンドはたくさんありますので、勉強したら追加したいと思います。
Dockerについて少し勉強しましたが、まだまだ理解不足な部分が多く、間違って記述している部分もあるかと思います。
間違いがありましたら、訂正したいと思いますので、ご指摘のほどよろしくお願いします。
- 投稿日:2019-08-16T21:18:04+09:00
Docker初心者に試して欲しい、VSCodeでDockerを簡単に使って開発する(PythonでHelloworldまで)
Dockerを少しづつ弄ってみてはいたのですが、開発環境として使うには、色々な知識が必要だったり、コマンド打ったりとか、中々初心者には敷居が高かったのですが、今年リリースされたVisualStudioCodeの
Remoteという拡張機能を使う事で、Docker内でのデバッグなども簡単にできるようになりました。難しい事抜きに、とりあえずDokcer使ってみたい!!という人にもおすすめです。
対象
- とりあえず、Docker触ってみたい
- Docker使いたいけど、コマンド打つのメンドくさい
事前準備
- DockerHubアカウント
- VisualStudioCodeインストール
- GitHubアカウント
GitHubでリポジトリ作成〜クローン
とりあえず、勉強用でもGitHubでリポジトリ作っちゃうのをおすすめします。
この辺は特に問題ないと思いますので、サクっと作っちゃいましょう。できたら、次はクローンですね。
CloneorDownloadからサクっとクローンしちゃいます。
ここで、GitHubDesktopをインストールしておくと、クローン〜VSCodeでリポジトリのディレクトリ開くまでがシームレスに行えるので、簡単ですよね。
クローンが終わったら、あとは、そのまま開くだけですね。
Open in Visual Studio CodeでサクっとVSCode開きましょう。VSCodeでDocker環境構築
次に、VSCodeの拡張機能のRemoteをインストールします。
終わったら、左下に
><こんなマーク出てるのわかりますか?
そこをクリックします。次に出てきたダイアログの中の一番上の
Remote-Containers:Open in Container...を選びます次に出てくるダイアログで、Dockerの環境を選べますので、今回は
Python3を選びます。ここで、Dockerコンテナのビルドが走りますので、少し時間がかかります。
ビルドが終わったら、VSCodeの中は、既にDockerに接続されている状態です。
試しに、HelloWorld.pyというファイルを作ってみましょう。ここで、追加でおすすめの拡張機能が、VSCodeのPython拡張機能です。
Pythonの普通のファイルをJupyterNotebookのように使う事ができます。この拡張機能をインストールして、一番最初の行に
# %%と書けば、あとはJupyterNotebookのようにShitf+Enterで実行ができるようになります。試しに、Helloworldを書いて、
Shift+Enterで実行してみましょうか。
右下に、Jupyterインストールする?って聞いてくると思うので、OKでインストールしちゃいましょう。(ごめんなさいSS撮り忘れました・・・)
Jupyterインストール後、再度実行した結果が下のような感じです。イエイ!!
ここまで、コマンド叩く事なく、GUIのみの操作でできましたね。あとがき
Dockerをチームで使って開発を行いたかったのですが、個人的にコマンドって覚えにくいし、打ち間違うしで、あまり使いたくなかったんですよね。
ですが、Remote拡張機能のおかげで、開発環境の構築が全てGUIで行えるようになったので、とても便利になりました。
リポジトリ作成〜コンテナでの開発開始まで、慣れれば3分もあればできるので、色々な環境の色々な言語でのトライ&エラーがやりやすくなりました。
- 投稿日:2019-08-16T20:52:04+09:00
Mono Docker で ASP.NET MVC (.NET Framework 4.7.2)
これはなに?
.NET Framework 4.7.2 でビルドしたASP.NET MVC アプリを、Linux Dockerで動かそうと試した備忘録です。
作戦
- Monoのイメージは公式のものを利用
- ASP.NETアプリは fastcgi-mono-server4 で動かす
- Nginxでホスティングし、fastcgi-mono-server4 とは unix domain socketで通信させる
- fastcgi-mono-server4 は Supervisorでサービス起動する
- NginxとMono(fastcgi-mono-server4)のコンテナは分ける
- Monoのバージョンはlatestではなく、5.18.1.28で検証
- データベースは今は考えない
完成した docker-compose 一式はこちら(Github)
サンプルアプリ
まずは VisualStudio でサンプルアプリを作ります。
ASP.NET MVCプロジェクトの雛形に用意されているサンプルにちょっとページを追加して、環境変数などを表示するようにしました。
(どっかで見たことのあるデザインですが・・・)
このアプリを「発行」して、一式をLinuxサーバに転送します。Mono Dockerイメージの調査
公式のDockerイメージがナンボのもんか知るためにシェルに入って調査します。
※サンプルアプリは、/home/mono-docker/app/aspinfo に配置していますホスト# docker run -v /home/mono-docker/app:/home/monoapp -p 9000:9000 -i -t mono:5.18.1.28 /bin/bashxsp4
MonoのWebサーバ (xsp と fastcgi-mono-server)は含まれていないようなので、インストールします。
ついでにSupervisor と vim も入れます。コンテナ# apt update # apt -y install mono-xsp4 mono-fastcgi-server4 supervisor vim簡易サーバ xsp を使ってアプリの動作を確認します。
コンテナ# cd /home/monoapp/aspinfo # xsp4 xsp4 Listening on address: 0.0.0.0 Root directory: /home/app/aspinfo Listening on port: 9000 (non-secure) Hit Return to stop the server.この状態でLAN内のWebブラウザから
http://Linuxホスト:9000を叩いてページが出ることを確認します。Supervisor
次にSupervisorの設定と起動の確認を行います。
実はここで大ハマリしました。Nginxとunix socket通信を行うには、お互いの実行ユーザがsocketに対して書き込み権限がある必要があります。
普通にSupervisorからfastcgiを起動すると、root所有の755でsocketが作成されるため、Nginxが通信できなくなります。
socketファイルは、DockerfileのCMDで Supervisorを起動したあとに作成されるため、後からパーミッションを変更することもできません。
PHP-FPMのように、socketファイルのパーミッションを指定できればよいのですが、fastcgi-mono-serverにはそんな機能が無いのです。仕方ないので、socketが作られるディレクトリを777で作成し、Nginxの実行ユーザと同じIdを持つユーザを作成し、fastcgi-mono-server はこのユーザで起動するようにします。
※Nginxのコンテナはいじりたくないので、Mono側がNginxのユーザに合わせるようにしていますNginx の Docker は、ユーザid が "101"の"nginx"ユーザで実行されるようです。
Since 1.17.0, both alpine- and debian-based images variants use the same user and group ids to drop the privileges for worker processes:
$ id
uid=101(nginx) gid=101(nginx) groups=101(nginx)なのでこれと同じユーザを作ります。
コンテナ# useradd -u 101 -U -s /sbin/nologin -d /home/monoapp -m nginx
また、socketファイル用ディレクトリを777で作成します。コンテナ# mkdir -p /var/run/xsp4 # chmod 777 /var/run/xsp4
これを受けて、fastcgi-mono-server 起動用の設定ファイルを作成します。コンテナ:/etc/supervisor/conf.d/xsp4.conf[supervisord] nodaemon=true [program:xsp4] directory=/home/monoapp/aspinfo environment=MONO_IOMAP=all command=fastcgi-mono-server4 /applications=/:/home/monoapp/aspinfo/ /filename=/var/run/xsp4/mono-xsp4.socket /socket=unix user=nginx autostart=true autorestart=true
Supervisorの試運転# supervisord & [1] 775 /usr/lib/python2.7/dist-packages/supervisor/options.py:298: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security. 'Supervisord is running as root and it is searching ' 2019-08-16 10:17:06,882 CRIT Supervisor running as root (no user in config file) 2019-08-16 10:17:06,884 INFO Included extra file "/etc/supervisor/conf.d/xsp4.conf" during parsing 2019-08-16 10:17:06,916 INFO RPC interface 'supervisor' initialized 2019-08-16 10:17:06,918 CRIT Server 'unix_http_server' running without any HTTP authentication checking 2019-08-16 10:17:06,920 INFO supervisord started with pid 775 2019-08-16 10:17:07,933 INFO spawned: 'xsp4' with pid 778 2019-08-16 10:17:08,942 INFO success: xsp4 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) # ps axu USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.3 18152 3248 pts/0 Ss 09:29 0:00 /bin/bash root 775 0.7 1.9 57920 20212 pts/0 S 10:17 0:00 /usr/bin/python /usr/bin/supervisord nginx 778 0.5 2.8 293076 28932 pts/0 Sl 10:17 0:00 /usr/bin/mono /usr/lib/mono/4.5/fastcgi-mono-server4.ex root 783 0.0 0.2 36636 2856 pts/0 R+ 10:19 0:00 ps axuうまく動きました
docker-compose
これらを踏まえて、MonoとNginxのコンテナを作成します。
ディレクトリ構成はこんな感じ
docker-compose.yml
Nginxは alpine ベースを使ってみました。
イメージのサイズは21.2MBとそこそこ軽量です。(1.17.3時点の値)docker-compose.ymlversion: '3' services: mono: build: ./mono volumes: - ./app:/home/monoapp - xsp4socket:/var/run/xsp4 nginx: image: nginx:alpine ports: - 80:80 depends_on: - mono volumes: - ./nginx/default.conf:/etc/nginx/conf.d/default.conf - ./nginx/fastcgi_params:/etc/nginx/fastcgi_params - ./app:/home/monoapp - xsp4socket:/var/run/xsp4 volumes: xsp4socket:mono
調査した操作をDockerfileに記述し、イメージを作成します。
Supervisorの設定ファイルをコピーし、CMDで起動します。mono/DockerfileFROM mono:5.18.1.28 RUN apt update \ && apt -y install mono-xsp4 mono-fastcgi-server4 supervisor \ && useradd -u 101 -U -s /sbin/nologin -d /home/monoapp -m nginx \ && mkdir -p /var/run/xsp4 \ && chmod 777 /var/run/xsp4 \ && mkdir -p /etc/mono/registry \ && chmod 777 /etc/mono/registry COPY ./xsp4.conf /etc/supervisor/conf.d/ CMD ["/usr/bin/supervisord"]mono/xsp4.conf[supervisord] nodaemon=true [program:xsp4] directory=/home/monoapp/aspinfo environment=MONO_IOMAP=all command=fastcgi-mono-server4 /applications=/:/home/monoapp/aspinfo/ /filename=/var/run/xsp4/mono-xsp4.socket /socket=unix user=nginx autostart=true autorestart=trueNginx
サイトの設定ファイル。
fastcgi-mono-server と unix domain socket で通信を行います。nginx/default.confserver { listen 80; root /home/monoapp/aspinfo; server_name _; location / { index index.html index.htm default.aspx Default.aspx; fastcgi_pass unix:/var/run/xsp4/mono-xsp4.socket; include /etc/nginx/fastcgi_params; client_max_body_size 10M; # upload limit } # favicon.ico location = /favicon.ico { log_not_found off; access_log off; } }
fastcgi-mono-server用の設定を追記したパラメータファイルnginx/fastcgi_paramsfastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; # for Mono configration fastcgi_param PATH_INFO ""; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;起動
ホスト# docker-compose up -d --build
うまく行けば、サンプリアプリが動きます。
ちゃんと Nginx経由 / unix OS で動いていると確認できます
感想
- ニッチなソリューションなため、情報が少なくて困りました
- とっとと.NET Coreに移行したいです
- 投稿日:2019-08-16T20:49:06+09:00
Laravel環境を3分で構築する【ついでにDocker入門】
うわあああああ!Laravelが使いたいよおおおお!
だけどサーバー構築面倒くさいよおおおお!!!!生きてるとそんなときもありますよね。
大丈夫、3分あればできます。実はもう別の方がQiitaに投稿されているのですが、Docker入門にもちょうどいいので少しだけ多めに解説した記事になります。
Docker で Laravel 環境 を 3分くらいで作る対象読者
- Dockerなんて(ほとんど)わかんない人
- でもとにかく一刻も早くLaravelを使いたい人
上記記事より
これだけです。
DBMSは MariaDB となっているようです。
https://github.com/bitnami/bitnami-docker-laravel
$ mkdir ~/myapp && cd ~/myapp $ curl -LO https://raw.githubusercontent.com/bitnami/bitnami-docker-laravel/master/docker-compose.yml $ docker-compose up解説するよ
何をしているのかを堅苦しくいうと、
「WordPressのローカル構築用ソフトを開発しているBitnamiが公式に提供しているDockerイメージをdocker-composeで一気に準備して起動している」
といったところでしょうか。素晴らしいことに、この3行だけで本当に仮想Docker環境を手元に用意することができてしまいます。
こちらを少しだけ詳細に解説してみましょう。
※Dockerのインストールだけは先に済ませておいてください1行目はいいですよね。
適当なフォルダを作って移動するだけです。
次にcurlコマンドでdocker-compose.ymlファイルを入手します。なんだそれは、と思われた方もいるかもしれません。
中身を見てみましょう。docker-compose.ymlversion: '2' services: mariadb: image: 'bitnami/mariadb:10.1' environment: - ALLOW_EMPTY_PASSWORD=yes - MARIADB_USER=my_user - MARIADB_DATABASE=my_database - MARIADB_PASSWORD=my_password myapp: tty: true image: bitnami/laravel:5-debian-9 environment: - DB_HOST=mariadb - DB_USERNAME=my_user - DB_DATABASE=my_database - DB_PASSWORD=my_password depends_on: - mariadb ports: - 3000:3000 volumes: - ./:/app # privileged: true # Privileged mode could be required to run this container under Windowsdocker-composeは複数のコンテナを一元管理するためのツールです。
詳しくはこちら。
DockerComposeの基本簡単に言うと、こちらのymlファイルでは"mariadb" と "myapp" 、それぞれの仮想環境(=Dockerコンテナ)を2つ手元に起動しますよ! という起点が定義されています。
"mariadb" がDBサーバ、"myapp" がwebサーバ兼APサーバですね。Laravelに触れてるとこの言葉自体もなかなか聞かなくなりますが……さて、3行目の
$ docker-compose upを入力するとお察しの通り念願のDockerコンテナが起動するわけですが、少しお待ちを。
先にこの超便利ツールをインストールしちゃいましょう。
(すでに3分超えてると思いますが、そこは触れないでください)DockerとDocker ComposeのTerminal UI「lazydocker」のご紹介
これはDockerにあまり触れる機会がない方でもパッと使える素晴らしいツールです。
さて、この状態で例の
$ docker-compose upを実行してみましょう。
実行!なんか2つrunningの状態になっていますね。
これが先程docker-compose.ymlファイルで確認した2つのコンテナです。
もうこの状態で2つのサーバがローカルで動いているような状態になっています。このサーバを停止、再起動したりするのもlazydocker上から簡単にできるので、先の記事を参考にしながらぜひやってみてください。
また、「本当にサーバとして起動している」のを実際に中に入って確認してみたい場合、
$ docker exec -it myapp_myapp_1 /bin/bash
で入ってみることができます。
この操作もlazydocker上からできるのですが、macで利用する場合上下ボタンが効かなくなるんですよね……閑話休題。
さて、いよいよ http://localhost:3000/ にアクセスしてみましょう。
Hello, Laravel!
簡単ですね。実際のソースコードは先程作った"myapp"ディレクトリに展開されています。
ローカルのコードを仮想環境が共有して使っているイメージですね。なので、ローカルのコードをちゃちゃっといじればブラウザ側のLaravelの動作に即座に反映されます。この方法で構築すれば、デバッグも可能です。
こちらの記事で完璧にまとめてくださっているので、ぜひお読みください!
Dockerで構築したPHP環境をxdebugでデバッグ(vscode)今回はこのあたりで。
- 投稿日:2019-08-16T20:39:57+09:00
DockerでChainer+JupyterLabを構築してみた
機械学習やディープランニングのChainerというフレームワークがあると知ったので、
遊びでDockerで構築してみた。GitHub
できたやつ
https://github.com/tubutubumustard/chainer_docker.gitDockerfile
DockerfileFROM ubuntu:16.04 WORKDIR /workdir RUN apt-get update -y && \ apt-get install -y --no-install-recommends \ python3-dev \ python3-pip \ python3-wheel \ python3-setuptools \ git \ g++ \ make \ cmake \ libblas3 \ libblas-dev \ && \ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* RUN pip3 install --upgrade pip RUN export CHAINER_BUILD_CHAINERX=1 RUN export CHAINERX_BUILD_CUDA=1 RUN pip3 install -U --no-cache-dir \ 'ideep4py<2.1' \ cupy-cuda92==6.2.0 \ chainer==6.2.0 \ scikit-learn \ pandas \ matplotlib \ jupyterlabDockerfileは下記を参考にして作成しました。
https://hub.docker.com/r/chainer/chainer/dockerfile
https://github.com/chainer/chainer/blob/master/docker/intel/python3/Dockerfile
WORKDIR /workdirはJupyterLabで作業するためのディレクトリになります。
iDeepとCuPyをインストールしていますが、
僕のノートパソコンにはNVIDIAのGPUは入ってないので、
iDeepで計算することになります。
DockerでCuPyを使用したい場合は、色々設定しないといけないみたいです。
(気が向いたらやってみようかな?)docker-compose.yml
docker-compose.ymlversion: '3' services: chainer: build: ./ volumes: - ./workdir:/workdir command: jupyter lab --port 8000 --ip=0.0.0.0 --allow-root --NotebookApp.token='' ports: - 50020:8000docker-compose.ymlでは、遊び用なので、
JupyterLabをrootの起動の許可と、tokenを無効にしています。コンテナを起動して、JupyterLabにアクセスする
sh$ docker-compose up -dブラウザでアクセスする
Chainerのバージョンや実行環境を確認
Chainerのチュートリアルを動かしてみるちなみに
CuPyを使おうとすると、怒られる終わり
本格的に機械学習やディープランニングの練習するなら、専用のサイトが用意しているみたいなので、そっちを使おう!
- 投稿日:2019-08-16T19:11:01+09:00
【チートシート】Dockerの使い方
一時コンテナ作成
docker pull イメージ
docker run --rm -it 【コンテナ名指定】/bin/bash (—rmはexit後にコンテナを削除)Dockerfileがある場合のイメージビルド
docker build ./ -t 【タグ(イメージ名前)】
コンテナの作成と起動
docker run -it -d —name 【コンテナ名指定】【上記で指定したタグ(イメージ名前)】 (-p ホスト:コンテナ)
コンテナの中に入る
docker exec -it 【上記で指定したコンテナ名指定】/bin/bashコンテナプロセス確認
docker ps (-aで止まっているコンテナも表示)
コンテナ停止と起動
docker stop/start 【コンテナ名】
コンテナイメージの削除
docker rm 【コンテナ名】
docker rmi 【イメージ名】全コンテナ停止
docker stop $(docker ps -q)
全コンテナ削除
docker rm $(docker ps -q -a)
全イメージ削除
docker rmi $(docker images -q)
容量の確認と不要なコンテナイメージ削除
docker system df
docker system prune<Dockerfile書き方>
RUN→イメージ作成時
COPY→ディレクトリのコピー
CMD→コンテナ起動時
WORKDIR→コンテナ内でcdコマンド
- 投稿日:2019-08-16T18:50:39+09:00
vuejsでsuggestフォームを作る2
前回はvue.jsをDockerで動かすところまで進めました
第2回目はDockerにElasticsearchの環境をつくるところまでですやりたいことのおさらい
キーワードを入力していくとキーワード候補エリア、関連エリア(もしかして、、、これ?みたいな)が表示されるやつを作ります
Elasticsearch環境作成
1.Dockerfileを作成
Install Elasticsearch with Docker を参考にDockerfileを作ります
ディレクトリ構成はこんな感じにします
$ tree . ├── Makefile ├── docker-compose.yml ├── dockerfile │ ├── elasticsearch │ │ └── Dockerfile │ └── vue │ └── Dockerfiledockerfile/elasticsearch/DockerfileFROM docker.elastic.co/elasticsearch/elasticsearch:6.7.2 RUN elasticsearch-plugin install analysis-kuromoji日本語を扱いたいのでkuromojiをinstallしています
2.docker-compose.yamlを作成
docker-compose.yamlversion: '3' services: vue_app: build: dockerfile/vue ports: - 9000:9000 volumes: - .:/app stdin_open: true tty: true command: /bin/sh elasticsearch: build: dockerfile/elasticsearch ports: - "9200:9200" volumes: - esdata1:/usr/share/elasticsearch/data networks: - esnet volumes: esdata1: driver: local networks: esnet:コンテナ削除後でもデータを利用できるように
データボリュームを作成しておきます3.起動
$ make start4.起動確認
$ curl -XGET localhost:9200 { "name" : "xxx", "cluster_name" : "docker-cluster", "cluster_uuid" : "xxx", "version" : { "number" : "6.7.2", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "56c6e48", "build_date" : "2019-04-29T09:05:50.290371Z", "build_snapshot" : false, "lucene_version" : "7.7.0", "minimum_wire_compatibility_version" : "5.6.0", "minimum_index_compatibility_version" : "5.0.0" }, "tagline" : "You Know, for Search" }次回はElasticsearchにテストデータを用意する予定です
- 投稿日:2019-08-16T17:22:28+09:00
docker,docker-composeでちょっと使うコマンド
dockerで今あるやつみる
docker ps -a docker imagesdocker-compose buildが反映されてないっぽいとき
docker-compose build --no-cache全部消したいとき
container全削除
-fをつけたら強制的になる
docker rm `docker ps -a -q`image全削除
-fをつけたら強制的になる
docker rmi `docker images -q`全部は消したくない系
例えば、今日の作業分全部いらないなってときに
dockerで今日のcontainer全部消す
-fをつけたら強制的になる
docker rm `docker ps -a | grep -E "minutes|minute|hours|hour" | awk '{print $1}'`dockerで今日のimage全部消す
-fをつけたら強制的になる
docker rmi `docker images | grep -E "minutes|minute|hours|hour" | awk '{print $3}'`
- 投稿日:2019-08-16T17:06:38+09:00
mongo-go-driverがうまく入らなかったので、手動でいれた。
概要
mongo-go-driverをDockerfileなり、自動で入れようとしたら上手くいかず、手動でいれるとうまくいったので、その共有。
誰かが同じ轍を踏まないように。mongo-go-driver
Go Runtimeコンテナ
base image => golang:1.12.8 ※2019/08/15時点でのstable versionアタッチして下記を実行
パッケージ管理ツール: depのインストール
$ curl https://raw.githubusercontent.com/golang/dep/master/install.sh | shProjectの初期化
$ dep init ※project rootでMongo Driverのインストール
$ dep ensure --add go.mongodb.org/mongo-driver/mongo go.mongodb.org/mongo-driver/bson go.mongodb.org/mongo-driver/mongo/options※goファイルでimportしていない場合、「これはまだ仮のインストールでっせ」という警告が出るかもしれませんが、
importすれば、消えるので無視でOKあとはdocker commitなりなんなり。
参考
- Github: mongo-go-driver
- MongoDB公式ドキュメント
- 投稿日:2019-08-16T16:10:40+09:00
Docker上で動いているMastodonをkubernetesクラスタに移動した作業メモ
本稿のスコープ外
- Kubernetes(以下 k8s)クラスタの構築方法
- Mastodonの初期設定
- kustomizeのインストール
※ 多少読み替えて頂ければ、dockerではないMastodonも移行できるはず
前提条件
- kubectlが実行可能なこと
- kustomize が使用可能なこと
- 以降元dockerコンテナのファイルを持ってこれること
作業手順
実は移行自体はそれほど難しくありません。
移行が必要なのは、PostgreSQLのDBだけです。redisのデータも移行した方がよいですが、
移行しなくてもその時点のSidekiqのジョブが失われる程度で、恐らく誰も気づきません。
※ 管理者的には、Sidekiq画面のジョブ数がリセットされるのが残念かな?程度kubernetesクラスタ上にPodを生成
Deployment定義をgithubに公開しています。
https://github.com/yakumo-saki/k8s-mastodon-deployment
私のインスタンスは、Glitch EditionなのでDockerイメージ名が違いますが、基本的に
公開しているDeploymentをそのまま使用しています。
複数インスタンス持ちなので、myinstanceをコピーして foundation としました。
foundation/kustomize.yamlは以下のように書き換えました。namePrefix: foundation- commonLabels: app: foundation resources: - ../base configMapGenerator: - name: config env: env.production files: literals:
env.productionファイルは稼働中のインスタンスからそのまま持ってきます。
その上で、DB_HOSTREDIS_HOSTを変更します。base/kustomization.yaml変更
DBを戻し終わるまでは、Web, Streaming, Sidekiqには起動して欲しくありません。
そのため、一時的に./base/kustomization.yamlを変更します。resources: - db-service.yaml - db-pvc.yaml - db-statefulset.yaml - web-sidekiq-pvc.yaml - redis-service.yaml - redis-pvc.yaml - redis-deployment.yaml #- web-service.yaml ここから下をコメントアウト #- web-deployment.yaml #- streaming-service.yaml #- streaming-deployment.yaml #- sidekiq-deployment.yamlここまでできたら、
foundationディレクトリで
```bash
$ kustomize build | kubectl apply -f -configmap/foundation-config-4dm8g6h6gm created
(略)
```移行元インスタンス停止
(リハーサルなら止めなくてよい)
DBとRedisコンテナ以外 を停止します。DB, redis バックアップ取得
# 移行元インスタンスのdockerが動いてるところで $ docker exec mastodon_db_1 pg_dumpall > pg_dumpall.sql # このコマンドはredisへのアクセスが停止します。(短時間ですが) $ docker exec mastodon_redis_1 redis-cli save OK $ docker cp mastodon_redis_1:/data/dump.rdb .
pg_dumpall.sqldump.rdbファイルは、kubectlを使用可能なPCにコピーしておいて下さい。DBバックアップをk8s上のDBに戻す
$ kubectl cp pg_dumpall.sql foundation-db-0:pg_dumpall.sql $ kubectl exec -it foundation-db-0 sh $$ psql root=# \i pg_dumpall.sql (どばっと、DUMP取込のログが出る) root=# quit # SQLファイルを消しておかないとサーバーの容量を食うため(コンテナ再起動で消えますが) $$ rm pg_dumpall.sqlRedisバックアップをk8s上のDBに戻す
redisのバックアップは、 /data/dump.rdb を上書きするだけです。
しかし、一つ落とし穴があります。 それは、redis稼働中にdump.rdbを上書きしても、
redisをシャットダウンする際に上書きされるという罠です。
なので、一旦redis-serverを起動しないようにします。
./base/redis-deployment.yamlを編集。./base/redis-deployment.yaml(略) containers: - name: redis image: redis:5.0-alpine command: ["tail", "-f", "/dev/null"] # この行追加(またはコメントアウト解除) resources: requests: memory: "16M" livenessProbe: # exec: # ここをコメントアウト # command: # - redis-cli # - ping (略)$ kubectl get pod して、 foundation-redis-* のpod を探す。 $ kubectl cp dump.rdb foundation-redis-xxxx:dump.rdb_new $ kubectl exec -it foundation-redis-xxxx sh $$ ps aux PID USER TIME COMMAND 1 root 0:00 tail -f /dev/null # redis-server が動いていないことを確認 52 root 0:00 sh 72 root 0:00 ps aux $$ ls -lh -rw-r--r-- 1 redis redis 92 Aug 16 05:06 dump.rdb -rw-r--r-- 1 501 dialout 5.3M Aug 16 05:28 dump.rdb_new # 所有者が違う! $$ cp dump.rdb_new dump.rdb $$ chown redis.redis dump.rdb一時的に変更した設定ファイルの復元
- 編集した
./base/redis-deployment.yamlを元に戻します。- 編集した
./base/kustmization.yamlを元に戻します。元に戻したら、いよいよ起動を行います。
kustomize build | kubectl apply -f -動作確認
とりあえず、
curl [外向きのIP等]:3000して何かが帰ってくればOKとします。リバースプロクシの設定変更
動作確認ができたら、リバースプロクシの設定を変更しましょう。
積み残し
favicon
マウントしないといけないのですが、本稿では色々と事情があり割愛しています。
蛇足
.env.production じゃなくて env.productionにリネームしたのなんで?
.env.productionだとlsしたときに表示されないからです。ls -aすれば見えますが。
個人的に見えないファイルが重要っていうのはあんまり好きではないので。。単純に好みですね
- 投稿日:2019-08-16T15:54:57+09:00
Docker環境でHeadless Chromeを使ったSystemt Specを実行する
この記事なんやねん
みなさん、Rspecで統合テスト(System Spec)書いてますか?
すっかりSeleniumを使ってヘッドレスブラウザを使った統合テストが主流になりましたが、
DockerとHeadless Chromeを使ったやり方が意外とヒットしなかったので投稿します。手順
ここから早速始めていきましょう。因みに、以下の環境は揃っているという前提で進めます。
- Dockerとdocker-composeをインストール済み
- docker-composeを使ってRails環境を構築済み
- Rspec実行環境を構築済み
もし、 環境構築まだやねん って状態だったら、こちらの記事を参考に開発環境を作ってみてください。
イメージの準備
Dockerfileにheadless chromeドライバをインストールしてもいいのですが、正直めんどくさいです。
brewで簡単にインストールできるのにDocker使った方が環境構築めんどくさいのも本末転倒な感じするので、Dockerhubにイメージ上がってないか検索したら案の定ありました。https://hub.docker.com/r/selenium/standalone-chrome
seleniumがイメージを提供してくれてるようですね。因みに、googleはイメージ提供していないようなので、seleniumさんのイメージをありがたく使いましょう。
サービス追加
docker-composeに以下のように既存サービスの一番下にサービスを追加してください。
docker-copompose.ymlversion: '3' services: ### 省略 ### chrome: image: selenium/standalone-chrome ports: - "4444:4444"これだけです。やっぱりイメージ使えば楽ですなあ。
Rspecの設定
次に、Rspecの設定をしていきます。Capybaraとrails_helperを設定するだけで済むので簡単です。
Gemfileの修正
もしまだライブラリをインストールしていなければ以下を追記してから、
bundle installしてください。Gemfilegroup :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem "database_cleaner" gem "factory_bot_rails" gem "rspec-rails" # 下記を追加 gem 'capybara' gem 'selenium-webdriver' gem 'rspec-retry' endCapibaraの設定
下記のファイルを作成してください。ポート番号は他でもいいですよ。
spec/support/capybara.rbCapybara.default_driver = :selenium_chrome Capybara.javascript_driver = :selenium_chrome Capybara.server_host = Socket.ip_address_list.detect(&:ipv4_private?).ip_address Capybara.server_port = 3001 Capybara.default_max_wait_time = 5 Capybara.ignore_hidden_elements = true Capybara.register_driver :selenium_chrome do |app| opts = { desired_capabilities: :chrome, browser: :remote, url: "http://chrome:4444/wd/hub", } Capybara::Selenium::Driver.new(app, opts) endrails_helperの修正
下記のようにrails_helperを修正してください。
なお、spec/support/system_support.rbというSystemスペック用のヘルパーを
作成しなければ任意ってコメントしてる設定は不要です。spec/rails_helper.rb### 省略 ### # コメントアウトされてるので、コメントアウトを外してください Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } RSpec.configure do |config| ### 省略 ### # Systemスペック用のヘルパー。任意です。 config.include SystemSupport, type: :system # 名称を一意にするために設定。任意かな。 config.before(:all, type: :system) do timestamp! end # Systemスペックは不安定なのでリトライ用の設定。 config.verbose_retry = true config.display_try_failure_messages = true config.default_retry_count = 3 # 下記を追加 config.before(:each, type: :system) do driven_by Capybara.default_driver end config.before(:each, type: :system, js: true) do driven_by Capybara.javascript_driver host! "http://#{Capybara.server_host}:#{Capybara.server_port}" end endヘルパーの作成(任意)
Systemスペックは共通の処理(ログイン処理とか)が多いので、ヘルパーを用意しておくと便利です。
任意と書いていますが、作成しておいて損はないと思います。spec/support/system_support.rbmodule SystemSupport # 一意の名称を作成するために実行時のtimestampを、 # 数字でインスタンス変数に格納するsetterです。地味に便利。 def timestamp!(timestamp = Time.now.to_i) @timestamp = timestamp end # getterです def timestamp @timestamp end # ブロックの結果がtrueになるまでループするメソッド。すげえ使う。 def wait_until(wait_time = Capybara.default_max_wait_time) Timeout.timeout(wait_time) do loop until yield end end # 特定のcssが登場する、もしくは、なくなるまでループするメソッド def wait_for_css(selector, wait_time = Capybara.default_max_wait_time, non_display: false) Timeout.timeout(wait_time) do loop until send((non_display ? :has_no_css? : :has_css?), selector) end yield if block_given? end # 非同期通信が終わるまでループするメソッド def wait_for_ajax(wait_time = Capybara.default_max_wait_time) Timeout.timeout(wait_time) do loop until page.evaluate_script("jQuery.active").zero? end yield if block_given? end endSystem Specの作成
ここまでで設定は完了してるので実際にSystem Specを書いていきましょう。
私のサンプルソースではこんな感じで書いてます。自分のソースコードに合わせて適宜書き直してください。require "rails_helper" # typeはsystemを設定、Javascriptも使うのでjsもtrueにしておく。 RSpec.describe "HelloWorlds", type: :system, js: true do # 最初にテストデータ作成 before(:all) { create(:hello_world, country: "JP", hello: "こんにちわ世界", priority: 1, file_name: "jp.jpeg") create(:hello_world, country: "US", hello: "Hello World", priority: 2) create(:hello_world, country: "CN", hello: "你好 世界", priority: 3) } before(:each) { visit root_path # コンテンツが全て表示されるまで待つ wait_until { (page.all("div.portfolio-item").count == 3) } } context "when go to index page" do it "show contents" do expect(page).to have_css("h1", text: "Hello World") content = page.first("div.portfolio-item") expect(content.first("p.card-text").text).to eq("こんにちわ世界") expect(content.first("h4.card-title")).to have_link("日本") expect(content.first("img.card-img-top")[:src]).to match(/jp\.jpeg/) end end context "when go to Create page" do it "create content" do page.first("#new_hello_world").click # タイトル出るまで待つ wait_until { page.has_css?("h3", text: "New Helloworld") } select "ドイツ", from: "hello_world_country" # 一意の名称で検索してテストデータを作成 fill_in "hello_world_hello", with: "Hallo Welt #{timestamp}" fill_in "hello_world_priority", with: 4 click_on "Submit" # メッセージ出るまで待つ wait_until { page.has_content?("Hello world was successfully created.") } content = page.first("div.form").all("label.form-control") expect(content[0].text).to eq("ドイツ") expect(content[1].text).to eq("Hallo Welt #{timestamp}") expect(content[2].text).to eq("4") end end endテスト実行
早速テストを実行してみましょう。
下記のwebはサービス名なので適宜自分の設定してるサービス名に変更して実行してください。% docker-compose run --rm web rspec spec/system/hello_worlds_spec.rb Starting hr_chrome_1 ... done Starting hr_db_1 ... done Capybara starting Puma... * Version 4.1.0 , codename: Fourth and One * Min threads: 0, max threads: 4 * Listening on tcp://192.168.176.4:3001 .. Finished in 1 minute 1.58 seconds (files took 3.71 seconds to load) 2 examples, 0 failures通りましたね、やったぜ
まとめ
Dockerでも簡単にHeadless Chromeを使った統合テスト環境を実現できました。
テストだけじゃなくてスプレイピングにも利用できるので試してみてください。因みに、今回使ったサンプルソースはこちらのリポジトリになるので参考までにどうぞ。
- 投稿日:2019-08-16T15:26:08+09:00
KubeEdge環境を構築してみた by AWS EC2
TL;DR
KubeEdgeの公式手順に従ってKubeEdge環境をEC2インスタンス上に構築してみた
基本的には参考サイトに載っている手順に準じて構築している
構築までしかしていないので悪しからず!そもそもKubeEdgeとは?
CNCF(Cloud Native Computing Foundation)の配下で最近GAされたエッジコンピューティングフレイムワークのOSS
→ 詳しくはこちら
Kubernetes(以下、k8s)もCNCFによりGAされており、いわば本家お墨付きのようなエッジ用k8s
似たようなので、Rancherのk3sがある → GitHubはじめに
KubeEdge環境の構築には主に3通りの方法がある(詳しくはGHのUsage参照)
- 用意されたバイナリを実行し、k8s環境から全て自動構築する
- k8sの環境を自前で構築し、 リリースパッケージを使って構築する
- k8s環境を自前で構築し、ソースからビルドして構築する
今回は2つ目の方法で構築している、なぜか?
答え単純、1つ目の方法で上手くいかなかったからである!
※筆者は3回やって挫折
3度目に失敗してから「もう自分でやったほうが早いな」と思い至り2番目の方法で構築したらすんなりできた環境
今回は構築方法までなのでエッジ側もAWSのEC2インスタンスでお手軽に構築してみた
本来ならエッジ側はラズパイなどのデバイスになるはずである
以下、環境情報バージョン
全て最新版を使用した(2019年8月時点)
- Docker: 19.03.1
- Kubernetes: 1.15.2
- kubeedge: 1.0.0
マシンスペック
マスタを大きく設定したけど、こんなにいらなかった
これならローカルのVMでも動かせそうである
- master
- OS: Ubuntu 18.04 LTS
- CPU: 8
- Memory: 32GB
- Storage: 30GiB
稼働状況
Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ cpu 850m (21%) 100m (2%) memory 190Mi (1%) 390Mi (2%) ephemeral-storage 0 (0%) 0 (0%)
- worker
- OS: Ubuntu 18.04 LTS
- CPU: 2
- Memory: 4GB
- Storage: 15GiB
構築手順
本題である構築手順!
EC2インスタンスの立て方については書かないので悪しからず
公式に従い「kubeadm」でk8sクラスタを構築する共通
まずは必須であるDockerとk8s関連のパッケージをそれぞれにインストールする
sudo apt update sudo apt upgrade -y # アップグレードは筆者の好み、正直しない方がいいかもしれない # docker sudo su - apt-get update && apt-get install apt-transport-https ca-certificates curl software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" apt-get update && apt-get install docker-ce cat > /etc/docker/daemon.json <<EOF { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" } EOF mkdir -p /etc/systemd/system/docker.service.d systemctl daemon-reload systemctl restart docker systemctl status docker # k8s関連 apt-get update && apt-get install -y apt-transport-https curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - cat <<EOF >/etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF apt-get update apt-get install -y kubelet kubeadm kubectl apt-mark hold kubelet kubeadm kubectl echo 'KUBELET_EXTRA_ARGS=--cgroup-driver=systemd' > /etc/default/kubelet systemctl daemon-reload systemctl restart kubelet systemctl status kubelet # まだkubeletは動かないが問題ないマスタ
共通の構築ができたらまずはマスタを構築する
今回はCNIにArmでも動く「flannel」を使うsudo su - # for flannel kubeadm init --pod-network-cidr=10.244.0.0/16 sysctl -w net.bridge.bridge-nf-call-iptables=1 # KubeEdge用に編集する vim /etc/kubernetes/manifests/kube-apiserver.yaml - - --insecure-port=0 + - --insecure-port=8080 + - --insecure-bind-address=0.0.0.0 # flannelのPodをデプロイする kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml kubectl label nodes ip-172-31-38-225 type=master kubectl get nodes -L type # StatusがReadyになっているはず # KubeEdgeで使うCRDをデプロイする wget -L https://github.com/kubeedge/kubeedge/blob/master/build/crds/devices/devices_v1alpha1_devicemodel.yaml kubectl create -f devices_v1alpha1_devicemodel.yaml wget -L https://github.com/kubeedge/kubeedge/blob/master/build/crds/devices/devices_v1alpha1_device.yaml kubectl create -f devices_v1alpha1_device.yaml # KubeEdgeのリリースパッケージをダウンロード curl -LO https://github.com/kubeedge/kubeedge/releases/download/v1.0.0/kubeedge-v1.0.0-linux-amd64.tar.gz tar -xf kubeedge-v1.0.0-linux-amd64.tar.gz -C /etc # KubeEdgeで使う証明書を発行 wget -L https://github.com/kubeedge/kubeedge/blob/master/build/tools/certgen.sh chmod +x certgen.sh bash -x ./certgen.sh genCertAndKey edge # マスタ側のKubeEdgeを起動する cd /etc/kubeedge/cloud nohup ./edgecontroller > edgecontroller.log 2>&1 & tail edgecontroller.log # エッジ側に同じものを送るためにコピーしておく cp -r /etc/kubeedge /home/ubuntu chown ubuntu:ubuntu /home/ubuntu/kubeedge -Rローカル
今回はマスタ側で発行した証明書などをエッジ側にも置くためにローカルからSCPでコピーして送った
※マスタとエッジが直接SSHできるならこれはいらないscp -r -i ~/.ssh/aws/admin.pem ubuntu@<master-ip>:/home/ubuntu/kubeedge ~/ scp -r -i ~/.ssh/aws/admin.pem /home/ubuntu/kubeedge ubuntu@<edge-ip>:/home/ubuntu/エッジ
さて、マスタが構築できたらエッジを構築したk8sクラスタに参加させる
※「kubectl」をマスタ側で叩いているが、エッジでも叩けるようにすればどちらでも問題ない
→ 詳しくはこちらsudo su - # 送っておいたファイルを適切な場所に置いておく cp -r /home/ubuntu/kubeedge /etc chown root:root /etc/kubeedge -R # 構築したクラスタに参加させる ※適宜置き換える kubeadm join 172.31.38.225:6443 --token <token> \ --discovery-token-ca-cert-hash sha256:<ca-cert-hash> # in master # nodeの名前は適宜置き換える kubectl get nodes # 新しくnodeが追加されているはず kubectl lobel nodes ip-172-31-39-8 type=worker wget -L https://github.com/kubeedge/kubeedge/blob/release-1.0/build/node.json vim node.json - name: "fb4ebb70-2783-42b8-b3ef-63e2fd6d242e", + name: "ip-172-31-39-8", kubectl apply -f node.json # エッジ側のKubeEdgeを起動する cd /etc/kubeedge/edge vim conf/edge.yaml # nodeの名前を適切に修正する - url: wss://172.31.38.225:10000/e632aba927ea4ac2b575ec1603d56f10/fb4ebb70-2783-42b8-b3ef-63e2fd6d242e/events + url: wss://172.31.38.225:10000/e632aba927ea4ac2b575ec1603d56f10/ip-172-31-39-8/events - node-id: fb4ebb70-2783-42b8-b3ef-63e2fd6d242e + node-id: ip-172-31-39-8 - hostname-override: fb4ebb70-2783-42b8-b3ef-63e2fd6d242e + hostname-override: ip-172-31-39-8 nohup ./edge_core > edge_core.log 2>&1 & tail edge_core.logテスト
最後にちゃんと動いてるか、簡単に確認する
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/release-1.0/build/deployment.yaml kubectl get pods kubectl get deployおわりに
とりあえず動くものを構築してみた
最初の方にも書いたが、参考サイトに従って構築したので不明な点は参考サイトを参照してほしい
正直KubeEdge自体が正しく動いているか、確信が持ててない...
故に次は、KubeEdgeのExampleを試してみたいと思う
→ https://github.com/kubeedge/examples/tree/master/led-raspberrypi参考
- docker
- kubeadm(+flannel)
- KubeEdge
- 投稿日:2019-08-16T14:54:25+09:00
Docker compose 備忘録
Docker とか詳しく分かってない人が Swagger UI を docker で立ち上げるまでの docker-compose 備忘録
Docker インストール
Docker Hub の アカウント作成 & Docker desktop for mac をダウンロード
Docker desktop をインストール & インストールチェック
$ docker version Client: Docker Engine - Community Version: 19.03.1 API version: 1.40 Go version: go1.12.5 Git commit: 74b1e89 Built: Thu Jul 25 21:18:17 2019 OS/Arch: darwin/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.1 API version: 1.40 (minimum version 1.12) Go version: go1.12.5 Git commit: 74b1e89 Built: Thu Jul 25 21:17:52 2019 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.2.6 GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb runc: Version: 1.0.0-rc8 GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87f docker-init: Version: 0.18.0 GitCommit: fec3683launch
- swagger.yaml を作成
- docker-compose.yml を作成
- docker-compose.yml がある階層で
docker-compose up -dhttp://localhost:3200にアクセス- Swagger UI がブラウザで見れる!!!!
今回作成した階層構造はこうなりました。
swagger/ ├ swagger.yaml └ docker/ └ docker-compose.ymlコンテナの起動
docker-compose up
- コマンドを実行した階層の docker-compose.yml をもとにコンテナ起動
exit した場合はコンテナが終了するので
docker-compose up -dでデタッチモード (バックグラウンド) で起動すると動き続ける。
docker-compose start
- 停止中のコンテナ起動
コンテナの確認
docker-compose psordocker container ls$ docker-compose ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c50f725ebe68 swaggerapi/swagger-ui "sh /usr/share/nginx…" 25 hours ago Up 9 hours 80/tcp, 0.0.0.0:3200->8080/tcp docker_swagger_1コンテナの停止・削除
docker-compose stop
- コンテナ停止
docker-compose down
- docker-compose で作成されたコンテナ関連削除
docker-compose down -vで volume ごと削除Example
- 今回使用した docker-compose.yml の例
docker-compose.ymlversion: '3' services: swagger: image: swaggerapi/swagger-ui environment: API_URL: /swagger.yaml BASE_URL: / volumes: - ../swagger.yaml:/usr/share/nginx/html/swagger.yaml restart: no ports: - 3200:8080version
- 起動する docker の version
- 3 系が最新
services
- Docker でアプリケーションを動かすための各要素
- ls で確認したときの name になる
docker_swagger_1image
- 起動するコンテナのイメージ
- ローカルになければリモートから pull ってくる
environment
- 環境変数
- image 内の環境変数を設定
volumes
- マウントする設定ファイル/ディレクトリの指定
- ホスト内のファイル/ディレクトリ : マウントするファイル/ディレクトリのコンテナ内のパス
volumes: - ./dir:/var/www/dirホスト上の dir 内でファイルを作るとコンテナの dir 内にも作られる。
(docker-compose.yml から見た相対パス)一番上の例だと
../swagger.yamlを更新するとコンテナ内の/usr/share/nginx/html/swagger.yamlも更新される。restart
- 実行時に再起動するかどうか
option 挙動 no 再起動しない : デフォルト always 再起動する on-failure ? unless-stopped ? 今回は特に気にしてなかったので詳しく調べていません
ports
- コンテナの port 指定
参考
DockerをMacにインストールする(更新: 2019/7/13) - Qiita
Swagger 3.0のOAuth認証にCognito User PoolsのOAuth Clientを使う | DevelopersIO
- 投稿日:2019-08-16T14:42:34+09:00
AngularのためのDockerfileの書き方
皆さん、Angular使ってますか?
私は仕事でも趣味でもAngularを使うAngular大好き人間ですが、共同開発なんかで動作確認してもらうとき、
node入れて@angular/cli入れてng serveして…となってしまい、結構環境が汚れてしまうのが難点だなーと思っていました。あと、本番環境のとき
ng build --prodして出来たビルドファイルをWinSCPで直上げするのも何とかしたい。いちいちコマンド叩いてWinSCP開くのめんどくせぇ…でも
@angular/cliの便利さは捨てがたい…特にオートリロードが…というわけで、「AngularアプリをDockerの上で動かす」ことに挑戦してみましたので、知見を残しておきます。
仕様
- 本番環境としても開発環境としても使えること
- 本番環境ではnginxを用いること
- 開発環境ではオートリロードしたい
- 一つのDockerfileにまとめる
方法
Dockerのマルチステージビルドを使います。
Dockerfile### ベースステージ ### FROM node:lts-alpine as base # @angular/cliをグローバルインストール RUN npm install -g @angular/cli # ワーキングディレクトリの設定 WORKDIR /some-angular-app # package.jsonをコピー COPY ./package*.json /some-angular-app/ # 一度node_modulesを削除してからnpm install RUN rm -rf node_modules && npm install ### ビルドステージ ### FROM base as build # 全てのソースファイルをコピー COPY ./ /some-angular-app/ # 本番用ビルド RUN ng build --prod --output-path=./dist/build-by-docker ### プロダクションステージ ### FROM nginx:alpine as prod # ビルドステージで生成されたファイルをnginxの公開用ディレクトリにコピー COPY --from=build /some-angular-app/dist/build-by-docker /usr/share/nginx/html # nginx.confをコピー COPY ./nginx/default.conf /etc/nginx/conf.d/default.confDockerfileではソースのコピーとビルド処理、ビルド結果のコピーのみを行い、
主たるコマンドはdocker-compose.ymlに書きます。docker-compose.ymlversion: "3.4" services: node: build: context: ./ dockerfile: "Dockerfile" target: base ports: - "4200:4200" command: sh -c "ng serve --host 0.0.0.0 --poll=1000" volumes: - .:/some-angular-app - node_modules:/some-angular-app/node_modules tty: true volumes: node_modules: driver: "local"こちらは開発環境用のdocker-compose.ymlです。Dockerfileにおける
baseステージを継承して動きます。
volumesでソースコードをマウントしているため、Dockerfile内で特にCOPYをしなくてもこれで動きます。
node_modulesをマウント対象から除外するのを忘れないようにして下さい。commandですが、
ng serve --host 0.0.0.0 --poll=1000がミソです。Dockerコンテナは、ホストPCとlocalhostを共有していますが、コンテナ内で動いている
@angular/cliにはそんなことは知ったこっちゃないため、@angular/cliが言うところの「localhost」は、Dockerコンテナの「localhost」だけなのです。つまり、
--hostオプションで「同ネットワークに接続しているすべてのIPアドレス」からのアクセスを許可してあげなければなりません。また、オートリロードを正しく作動させるために、
--pollオプションでファイル変更状況をポーリングするように設定しています。単位はmsです。docker-compose.prod.ymlversion: "3.4" services: node: build: context: ./ dockerfile: "Dockerfile" target: prod ports: - "8080:80" tty: trueこちらは本番用のdocker-compose.prod.ymlです。
prodステージを継承して動きますが、特筆して何かをしているわけではありません。.dockerignore .git dist *Dockerfile* *docker-compose* node_modulesCOPY時にnode_modulesがコピーされないよう、.dockerignoreに書いておきます。
default.confserver { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html index.htm; include /etc/nginx/mime.types; gzip on; gzip_min_length 1000; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; location / { try_files $uri $uri/ /index.html; } }最後に、nginxのconfフォルダにコピーしている
default.confです。
Angularをnginxで動かすために必要な「すべてのURIに対するアクセスをindex.htmlに流す」処理を行っているだけです。適宜変更してください。立ち上げ方
# 開発 $ docker-compose up --build # 本番 $ docker-compose -f docker-compose.prod.yml up --buildまとめ
マルチステージビルドを使って、docker-composeコマンド一発でAngularアプリを立ち上げる環境を構築することができましたが、予想通りというかなんというか、直接ホストPCで
ng serveしたときよりはかなりビルドが重いです。他人の環境を汚さないようにするだけでもかなりメリットはありますが、自分がゴリゴリ開発する立場だったら素直にホストPCに
@angular/cli入れた方がいいと思いました。
- 投稿日:2019-08-16T13:36:21+09:00
WebスクレイピングしたデータをGrafana で可視化する ②構築編
前回の記事で
Python(スクレイピング) + Influxdb + Grafanaで作る、データの可視化について本記事で詳しく解説します。なお、本記事は解説を目的とします。
"手順に"興味がある方はリポジトリのREADMEをご参照ください。おさらい
前回記事の再掲。
※だいたいの構成検討とかは通勤中に(頭の中だけで)練っていたので、手を動かし始めたら1日で作れました。
各コンテナの役割
- app: 30秒間隔でWebサイトをスクレイピングする。取得したデータを加工し、時系列DB(Influxdb)に格納する
- influxdb: OSSの時系列データベース(time series database)
- grafana: グラフ表示を担当
そもそも何を可視化するの?
Amazonギフト券を割安で買い付けられるサービスが存在します。
ギフト券を現金化したい売り手と、安く購入したい買い手とのマッチングサービスで、一種の市場を形成しているわけです。
この市場を、株式市場や為替市場と同じようにチャート表示してみたい というのがモチベーションです。実際に作ったのは以下のようなチャート描画です(グラフ表示はGrafana ですが)。
スクレイピング
前置き
こんな記事書いといてアレですが、スクレイピングという手法はあまり胸を張って良いものではないと考えてます(※個人の意見です)。
数十秒~数分間隔のスクレイピングならまだしも、ミリ秒レベルの間隔でなんか実行してしまうと「それDoSじゃん」と思ってしまいます。したがって、本記事および成果物(Github)では 私が実際に実装したスクレイピングツールの宛先URLおよびサービスは晒しませんのでご理解お願いします。
スクレイピング実装
Pythonの
urllib3とBeautifulSoup4を利用。これらを利用したスクレイピング自体については詳しく解説しませんのでググってください。
ここでは、本ケースで取得したいデータの前提を記載します。まず、Webページ内に以下のような表(テーブル)があるとします。
そして、このページ要素から以下のデータを集めることを考えます
- 最も安い販売レート(最良レート): best_rate
- レートの平均値: avg
- ワーストレート: worst_rate
- 総枚数: amount_sum
さて、htmlのテーブル要素の場合大抵以下のような構成になっていると思います。
ここでポイントとなるのは、HTMLにはタグとその階層構造があるということです。
表の行要素(黄色の部分)とセル要素(緑の部分)がそれぞれtrタグとtdタグにあたり、セル要素をforループで取得していきます。
今回取得したいのはギフト券のレートと枚数なので、for ループで全ての要素をした後 必要なデータを抜き出していく流れです。
以下がコードの抜粋です。app/main.py(抜粋)import urllib3 import certifi from bs4 import BeautifulSoup def scrape(url): # HTTPリクエストを生成 http = urllib3.PoolManager( cert_reqs='CERT_REQUIRED', ca_certs=certifi.where() ) # 対象URLをHTTP GETして保持 res = http.request('GET', url) soup = BeautifulSoup(res.data, 'html.parser') table_body = soup.select_one('#tbody1') amounts = [] rates = [] for tr in table_body.find_all('tr'): temp_list = [] for td in tr.find_all('td'): temp_list.append(td.string) amounts.append(int(temp_list[0].replace('枚', ''))) # "チケット枚数"リストに追加 rates.append(float(temp_list[3].replace('%', ''))) # "レート"リストに追加 # 最良レート、ワーストレート best_rate = min(rates) ; worst_rate = max(rates) # レート平均(重みつき) avg = ... return {'best_rate': best_rate, 'worst_rate': worst_rate, 'avg': avg, 'amount_sum': sum(amounts)} # チケット枚数の総量: sum(amounts)「全ての要素をした後 必要なデータを抜き出して」いるのが以下の部分です。
amounts.append(int(temp_list[0].replace('枚', ''))) # "チケット枚数"リストに追加 rates.append(float(temp_list[3].replace('%', ''))) # "レート"リストに追加取得データの書き込み
ここまででスクレイピングの実行およびデータ加工が完了しました。
続いて取得データをInfluxdbに書き込みすれば良いのですが、Pythonのライブラリが準備されています。
したがって何も難しいことなく実装できます。なお、ここで書き込みを行う際にJSON形式のリクエストボディを生成するため、上述のスクレイピングの関数では辞書型オブジェクトを返すようにしています。
return {'best_rate': best_rate, 'worst_rate': worst_rate, 'avg': avg, 'amount_sum': sum(amounts)} # チケット枚数の総量: sum(amounts)app/main.py(抜粋)impoert os from influxdb import InfluxDBClient # influxdbへ書き込み処理を行う def insert(measurement, values): client = InfluxDBClient( host=os.environ['INFLUXDB_HOST'], port=os.environ['INFLUXDB_PORT'], database=os.environ['INFLUXDB_DATABASE'] ) json_payload = [ { "measurement": measurement, "fields": values } ] client.write_points(json_payload)書き込み先DBの情報は環境変数から取得します。
pythonが実行されるDocker コンテナの起動時に環境変数を定義するようDockerfile に記述します。app/DockerfileFROM docker.io/python:3.7.4-alpine3.10 RUN apk add --no-cache bash && \ pip3 --no-cache-dir install influxdb urllib3 beautifulsoup4 certifi COPY ./main.py /app/main.py ENV INFLUXDB_HOST="scraping_and_grafana_influxdb_1" \ INFLUXDB_PORT="8086" \ INFLUXDB_DATABASE="mydb"コンテナ名や起動ポート番号を変更する場合は適宜変更してください。あとデータベース名("mydb")も同様。
Influxdbのススメ
Influxdbは時系列データベースです。
簡単なクエリ実行を例に動きを見てみましょう。コンテナデータベース起動~データベース作成まで。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/influxdb 1.7 d1e103e42e17 4 weeks ago 258 MB $ docker run -d --rm --name influxdb -p 8086:8086 docker.io/influxdb:1.7 7a554*** $ docker exec -it influxdb influx -precision rfc3339 Connected to http://localhost:8086 version 1.7.7 InfluxDB shell version: 1.7.7 > show databases name: databases name ---- _internal > CREATE DATABASE sample_db > SHOW DATABASES name: databases name ---- _internal sample_db > USE sample_db Using database sample_dbテーブル作成~レコード挿入
ここで、Influxdbの用法について。
Influxdb では一般のRDBMSでいう所のTABLEをMEASUREMENTと呼称します。正にメトリクスと位置付けているんですね。そして、挿入クエリの書式は以下。
(引用元: Influxdb and time series data - Slideshare)面白いのは、レコードにおいてタグと値を分けています(「値」はVALUEと言うべきか、measurement と言うべきか...)。
タグは省略可能です。テーブル名とタグはカンマ区切り、VALUEはスペースの後記述します。
また、InfluxdbではCREATE TABLE文も省略可能です(正しくはCREATE MEASUREMENTですが)> SHOW MEASUREMENTS > > INSERT cpu,host=A,region=tokyo usage=0.6,LA=0.3 > > SHOW MEASUREMENTS # "CREATE MEASUREMENT"文は不要 name: measurements name ---- cpu > SELECT * FROM cpu name: cpu time LA host region usage ---- -- ---- ------ ----- 2019-08-13T16:05:25.964591986Z 0.3 A tokyo 0.6INSERT文で指定したVALUEは
usage=0.6,LA=0.3のみでしたが、自動的にタイムスタンプが付与されているのが分かります。
Influxdbでは、基本的にこのtimeカラムをがキーの1つとなるように設計するとGoodだと思います。データが取得出来たらGrafanaで可視化
割愛します。
プラグインを選択して進んでいくだけです。まとめ
とりあえず今回は自宅の仮想サーバで実現しました。
今後の展望としては、お勉強として以下のことにも少しずつ挑戦できたら楽しいなと思ってます。
- 自動テストを組み込んでみる
- DBに書き込みしたデータの信頼性担保(EFSを利用?)
- コンテナオーケストレーションツールを組み合わせてみる
- 投稿日:2019-08-16T12:52:26+09:00
これからIBM Cloud CLIをインストールする方へ
皆さん、こんにちは。戸倉彩です。
今回は、IBM Cloud をコマンドラインから操作することができるCLIのインストールについて解説いたします。イベントやセミナー等で目的に応じてIBM Cloud CLIのインストールで案内される方法はさまざまですが、こちらも合わせて参考にしていただけばと思います。
IBM Cloud CLI とは
IBM Cloud CLIは、IBM Cloudのリソースを管理するためコマンド・ライン・インターフェース(CLI)のことです。現時点では、Mac OX、Windows、Linuxに対応したIBM Cloud CLIが公式サイトから提供されています。
IBM Cloud Kubernetes Servive なども利用する場合は Developer Tools もまとめて1発インストールしておくのが便利!
IBM Cloudで提供されているサービスによって、IBM Cloud CLIに加えてIBM Cloud Developer Toolsと呼ばれている開発者ツールのプラグイン等をインストールする必要があります。後から追加する手間を考えると、初めから一度に最新のIBM Cloud CLIを含む一連のIBM Cloud 開発ツールをインストールしておくと役立ちます。
ここで紹介するコマンドを実行してインストールを行うと、最新のIBM Cloud CLIと下記のツールを一度に入手することができます。GitやDocker、Kubernetesなどを利用する場合に必要なコマンドも一緒にインストールされるので時間の短縮にもなります。
・ Homebrew (Mac のみ)
・ Git
・ Docker
・ Helm
・ kubectl
・ curl
・ IBM Cloud Developer Tools プラグイン
・ IBM Cloud Functions プラグイン
・ IBM Cloud Object Storage プラグイン
・ IBM Cloud Container Registry プラグイン
・ IBM Cloud Kubernetes Service プラグインインストールする前の準備
- IBM Cloud アカウント の取得する
- 次のシステム要件を満たしていることを確認する
- DockerはStable チャネル (安定版) を使用する必要があるため、バージョン 1.13.1 以上を利用する
- 一部の機能はWindows 10 Pro を実行していないとサポートされません
インストール方法
下記のコマンドを実行します。
・MacおよびLinux環境の場合curl -sL https://ibm.biz/idt-installer | bash・Windows環境の場合
Windows 10 Pro の場合、管理者としてPowerShellで次のコマンをを実行します。[Net.ServicePointManager]::SecurityProtocol = "Tls12"; iex(New-Object Net.WebClient).DownloadString('https://ibm.biz/idt-win-installer')参考リソース: IBM Cloud CLI および Developer Tools の概説
シンプルに IBM Cloud CLI のみをインストールしたい場合
必要最低限のIBM Cloud CLIをインストールしたい、もしくは上記の手順でインストールが上手く実行できなかった時は、公式サイトから直接インストーラーをダウンロードして、ローカルで実行するという方法があります。
- Mac OS X 64ビット: インストーラー
- Windows 64ビット: インストーラー
- Linux X86 64ビット: インストーラー
- Linux LE 64ビット (ppc64le): インストーラー
32ビットのバージョンの環境をお使いの場合は、GitHubのIBM-Cloudリポジトリから直接ダウンロード入手することが可能です。
参考リソース: スタンドアロン IBM Cloud CLI のインストールIBM Cloud CLI の始め方
IBM Cloud CLIが正常にインストールされたことを検証するには、helpコマンドを実行します。
ibmcloud helpIBM Cloudを実際に操作するためには、利用するIBM Cloud環境にloginコマンドでログインを行います。
ibmcloud login企業などでシングルサインオンを利用している場合には--ssoのオプションを追加してログインをしてください。
ibmcloud login --ssoIBM CloudにIBM Cloud CLIでログインは無事にできましたでしょうか?
あとは、IBM Cloudのサイトやhelpを参考にしながら、操作を行ってみてください。今回は以上です。お疲れ様でした!
Have a nice Geek Life♪
※Twitterで最新情報配信中 @ayatokura
- 投稿日:2019-08-16T10:06:22+09:00
Docker-composeで立ち上げてVS CodeでJupyterを使って、OpenCVで画像処理する開発環境を作った件
目的
Pythonで画像処理がしたくて開発環境を作ろうと思った次第です。
単体でやってる方は多かったけど、同時にやってる方がいなくて意外と時間かかったので自分用のメモ。
composeにしたのは毎回コマンド打つのが面倒だった。 ← 知識の浅さを露呈?
ついでにVS CodeでJupyterを使う。Dockerfileとdocker-compose.yml
Docker-composeでJupyterLabを簡単構築を参考に(まるマパクり)させてもらってdocker-compose.ymlを追加する。
そのままだとJupyterのimageしか使えないのでDockerfileに移す。docker-compose.ymlversion: '3' services: jupyterlab: # これだとJupyterのimageしか使えないのでDockerfileに移す # image: jupyter/datascience-notebook:latest build: . user: root environment: NB_UID: 1000 NB_GID: 100 GRANT_SUDO: "yes" volumes: - "./work:/home/jovyan" privileged: true ports: - "8888:8888" restart: unless-stopped command: start.sh jupyter lab --NotebookApp.token=''Dockerhubからjjanzic/docker-python3-opencvのimageを使う。
jupyter-dockerから使いたいimageをもってくる。DockerfileFROM python:3.7 ARG project_dir=/home/jovyan WORKDIR $project_dir FROM jjanzic/docker-python3-opencv # https://jupyter-docker-stacks.readthedocs.io/en/latest/using/selecting.html FROM jupyter/scipy-notebook:latest COPY requirements.txt requirements.txt RUN pip install -r requirements.txtあとはdocker-compose build & upでいける。
ちなみに、下記にしたかったがこれだとうまく立ち上がらない。。。
誰か理由を教えてください。。。Dockerfile(NG)FROM python:3.7 FROM jupyter/scipy-notebook:latest ARG project_dir=/home/jovyan WORKDIR $project_dir # 他に必要なものを入れる FROM jjanzic/docker-python3-opencv RUN pip install opencv-pythonJupyterをVS Codeで使う
Jupyterをブラウザで使う分にはこのままで問題ないが、せっかくならVS CodeでJupyterを使いたい。
VS Codeはローカルを参照しているので、拡張機能Remote - Containersを使ってDockerに入る。
使い方はこちらの方が分かり易くまとめてくれてるので参考にしてDockerを立ち上げる。VSCodeの左下角をクリックして、Remote-Containers: Open Folder in Containerを選択して、docker-compose.ymlのあるプロジェクトのルートディレクトリを選択しすると立ち上がる
普段使っている拡張機能が反映されないので.devcontainer.jsonのextensionsに追加する。
.devcontainer.json// See https://aka.ms/vscode-remote/devcontainer.json for format details or // https://aka.ms/vscode-dev-containers/definitions for sample configurations. { "dockerComposeFile": "docker-compose.yml", "service": "jupyterlab", "workspaceFolder": "/", "extensions": [ "ms-python.python", "donjayamanne.jupyter", "formulahendry.auto-close-tag", "formulahendry.auto-rename-tag", "coenraads.bracket-pair-colorizer", "dbaeumer.vscode-eslint", "msjsdiag.debugger-for-chrome", "ms-azuretools.vscode-docker", "donjayamanne.githistory", "huizhou.githd", "eamodio.gitlens", "oderwat.indent-rainbow", "ms-ceintl.vscode-language-pack-ja", "ibm.output-colorizer", "ryu1kn.partial-diff", "ionutvmi.path-autocomplete", "esbenp.prettier-vscode", "wallabyjs.quokka-vscode", "mechatroner.rainbow-csv", "ms-vscode-remote.remote-containers", "humao.rest-client", "shan.code-settings-sync", "shardulm94.trailing-spaces", "octref.vetur", "vscode-icons-team.vscode-icons", "wakatime.vscode-wakatime" ] }ちなみに、ここに書くのは拡張機能の名前の右側にあるやつを追加する。
一発でJsonに吐き出す方法が分からなかったので地道に追加した。
JupyterをVS Codeで使えた
ちなみに、Jupyterを入れると、"#%%"の上に"Run Cell"が出てくるのでクリックすると実行画面が表示される。
- 投稿日:2019-08-16T05:32:04+09:00
docker-composeでMongoDBのReplicaSetを構築する
背景
ScalaでMongoDBへMulti-document transaction接続するの続き. MongoDBへMulti-document transaction接続するためにはReplicaSetが必要になる. ReplicaSetを構築してみたけどMongoDBよく分からん.,, 試行錯誤して技術的に解決できない部分も含めてある程度腑に落ちたので整理してみた. Transactions
環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.14.5 BuildVersion: 18F132 $ docker --version Docker version 19.03.1, build 74b1e89 $ docker-compose --version docker-compose version 1.24.1, build 4667896bReplicaSet構成
最小構成のPrimary, Secondary, Arbiterとする. Replication
ReplicaSetのコンテナを定義する
Primary, Secondary, Arbiterをdocker-composeにて定義する. ディレクトリ構成, 各パラメータの意図は下記の通り.
$ tree . ├── docker-compose.yml └── volumes └── mongodb ├── docker-entrypoint-initdb.d ├── etc │ └── mongod-keyfile # Permission: 600 └── root ├── 000_init_replicaSet.js ├── 001_init_database.js └── 002_init_user.js
- Primaryコンテナ
- 初期設定用のrootアカウントを定義する
- 初期化スクリプトをVolume共有する
- 各コンテナ
- Multi-document transactionを使用したいのでMongoDBのVersionは4.xを指定する
- HostOSのPort用に各MongoDBコンテナのPortを切り分ける
- 認証鍵をVolume共有する
docker-compose.ymlversion: '3' services: # https://hub.docker.com/_/mongo mongodb-primary: image: mongo:4.2.0-bionic container_name: mongodb-primary hostname: mongodb-primary command: > mongod --port 27017 --replSet replset --auth --keyFile /etc/mongod-keyfile environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: password volumes: - ./volumes/mongodb/root:/root:ro # Initialize script - ./volumes/mongodb/etc/mongod-keyfile:/etc/mongod-keyfile:ro # Permission: 600 ports: - 27017:27017 networks: - replset depends_on: - mongodb-secondary - mongodb-arbiter restart: on-failure # https://hub.docker.com/_/mongo mongodb-secondary: image: mongo:4.2.0-bionic container_name: mongodb-secondary hostname: mongodb-secondary command: > mongod --port 27018 --replSet replset --auth --keyFile /etc/mongod-keyfile volumes: - ./volumes/mongodb/etc/mongod-keyfile:/etc/mongod-keyfile:ro # Permission: 600 ports: - 27018:27018 networks: - replset depends_on: - mongodb-arbiter restart: on-failure # https://hub.docker.com/_/mongo mongodb-arbiter: image: mongo:4.2.0-bionic container_name: mongodb-arbiter hostname: mongodb-arbiter command: > mongod --port 27019 --replSet replset --auth --keyFile /etc/mongod-keyfile volumes: - ./volumes/mongodb/etc/mongod-keyfile:/etc/mongod-keyfile:ro # Permission: 600 ports: - 27019:27019 networks: - replset restart: on-failure networks: replset: ipam: config: - subnet: 192.168.1.0/24 # Any初期化スクリプトを作成する
下記の技術的課題により各コンテナ起動後に初期化スクリプトにてReplicaSetを構築するアプローチを取る.
- コンテナ作成時には他コンテナを参照できないらしい Cannot configure replica sets with entrypoint-initdb #339
- スクリプトをコンテナの /docker-entrypoint-initdb.d に共有してもReplicaSetを構築できない mongo Initializing a fresh instance
ReplicaSet初期化スクリプト
000_init_replSet.jsrs.initiate( { _id : "replset" , members: [ { _id: 0, host: "mongodb-primary:27017" } , { _id: 1, host: "mongodb-secondary:27018" } , { _id: 2, host: "mongodb-arbiter:27019", arbiterOnly: true } ] } );データベース初期化スクリプト
001_init_database.jsvar testdb = db.getSiblingDB('test'); testdb.createCollection('test');JavaScript内でMongoDB shellの
use <database>が使用できないためdb.getSiblingDB(<database>)を使用する.ユーザー初期化スクリプト
002_init_user.jsvar testdb = db.getSiblingDB('test'); testdb.createUser( { user: 'test' , pwd: 'password' , roles: [ { role: 'root' , db: 'admin' } , { role: 'dbOwner' , db: 'test' } ] } ); testdb.getUsers();ReplicaSetの認証鍵を作成する
$ openssl rand -base64 756 > mongod-keyfile $ chmod 600 mongod-keyfile
--auth --keyfile <path-to-keyfile>オプションを指定せずにReplicaSetを構築すると認証エラーが発生したので公式に倣って認証鍵を設定する. Update Replica Set to Keyfile Authenticationhostsを定義する
$ sudo vim /private/etc/hosts +127.0.0.1 mongodb-primary +127.0.0.1 mognodb-secondary +127.0.0.1 mongodb-arbiterHostOS側にClientがいる環境だったので名前解決のために /private/etc/hosts に追加定義する. ClientがDockerNetwork内に共存するならDockerDNSで名前解決できるので /private/etc/hosts への追加定義は必要ない. コンテナの DNS を設定 Dokcer-docs-ja
MongoDBのReplicaSetを立ち上げる
初期化スクリプト, 認証鍵をディレクトリ構成の配置に格納する.
コンテナを起動する.
$ docker-compose up -dPrimaryコンテナで初期化スクリプトを実行する.
$ docker-compose exec mongodb-primary mongo admin -u root -p password /root/000_init_replSet.js $ docker-compose exec mongodb-primary mongo admin -u root -p password /root/001_init_database.js $ docker-compose exec mongodb-primary mongo admin -u root -p password /root/002_init_user.js
docker-compose downコマンドでdocker-composeをもとに構築された全てを削除できる.MongoDBのReplicaSetに接続する
MongoDB Scala Driverに下記URIを指定して接続できることを確認できた. MongoDB Scala Driver
test.infrastructure.mongodb.MongoDBConnector.scalapackage test.infrastructure.mongodb import com.typesafe.config.ConfigFactory import org.mongodb.scala.MongoClient object MongoDBConnector { private val config = ConfigFactory.load private lazy val mongodbUri = config.getString("infrastructure.mongodb.uri") val client = MongoClient(mongodbUri) // .close }application.confinfrastructure { mongodb { # username: test # password: password # database: test # host: mongodb-primary:27017, mongodb-secondary:27018 # replicaSet: replset uri = "mongodb://test:password@mongodb-primary:27017,mongodb-secondary:27018/?authSource=test&replicaSet=replset" } }[info] No tests to run for Test / testOnly 01:40:59.028 [pool-7-thread-2-ScalaTest-running-UsecaseSpec] INFO org.mongodb.driver.cluster - Cluster created with settings {hosts=[mongodb-primary:27017, mongodb-secondary:27018], mode=MULTIPLE, requiredClusterType=REPLICA_SET, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500, requiredReplicaSetName='replset'} 01:40:59.033 [pool-7-thread-2-ScalaTest-running-UsecaseSpec] INFO org.mongodb.driver.cluster - Adding discovered server mongodb-primary:27017 to client view of cluster 01:40:59.098 [pool-7-thread-2-ScalaTest-running-UsecaseSpec] INFO org.mongodb.driver.cluster - Adding discovered server mongodb-secondary:27018 to client view of cluster 01:40:59.106 [pool-7-thread-2-ScalaTest-running-UsecaseSpec] DEBUG org.mongodb.driver.cluster - Updating cluster description to {type=REPLICA_SET, servers=[{address=mongodb-secondary:27018, type=UNKNOWN, state=CONNECTING}, {address=mongodb-primary:27017, type=UNKNOWN, state=CONNECTING}] 01:40:59.157 [pool-7-thread-2-ScalaTest-running-TuneUsecaseSpec] INFO org.mongodb.driver.cluster - No server chosen by com.mongodb.async.client.ClientSessionHelper$1@d54dba6 from cluster description ClusterDescription{type=REPLICA_SET, connectionMode=MULTIPLE, serverDescriptions=[ServerDescription{address=mongodb-secondary:27018, type=UNKNOWN, state=CONNECTING}, ServerDescription{address=mongodb-primary:27017, type=UNKNOWN, state=CONNECTING}]}. Waiting for 30000 ms before timing out 01:40:59.219 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-secondary:27018] INFO org.mongodb.driver.connection - Opened connection [connectionId{localValue:2, serverValue:17}] to mongodb-secondary:27018 01:40:59.220 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-primary:27017] INFO org.mongodb.driver.connection - Opened connection [connectionId{localValue:1, serverValue:23}] to mongodb-primary:27017 01:40:59.276 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-secondary:27018] INFO org.mongodb.driver.cluster - Monitor thread successfully connected to server with description ServerDescription{address=mongodb-secondary:27018, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, version=ServerVersion{versionList=[4, 2, 0]}, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=49927070, setName='replset', canonicalAddress=mongodb-secondary:27018, hosts=[mongodb-secondary:27018, mongodb-primary:27017], passives=[], arbiters=[mongodb-arbiter:27019], primary='mongodb-primary:27017', tagSet=TagSet{[]}, electionId=null, setVersion=1, lastWriteDate=Fri Aug 16 01:40:50 JST 2019, lastUpdateTimeNanos=133745025150196} 01:40:59.276 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-primary:27017] INFO org.mongodb.driver.cluster - Monitor thread successfully connected to server with description ServerDescription{address=mongodb-primary:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, version=ServerVersion{versionList=[4, 2, 0]}, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=49535877, setName='replset', canonicalAddress=mongodb-primary:27017, hosts=[mongodb-secondary:27018, mongodb-primary:27017], passives=[], arbiters=[mongodb-arbiter:27019], primary='mongodb-primary:27017', tagSet=TagSet{[]}, electionId=7fffffff0000000000000001, setVersion=1, lastWriteDate=Fri Aug 16 01:40:50 JST 2019, lastUpdateTimeNanos=133745025119925} 01:40:59.279 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-primary:27017] INFO org.mongodb.driver.cluster - Adding discovered server mongodb-arbiter:27019 to client view of cluster 01:40:59.280 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-primary:27017] INFO org.mongodb.driver.cluster - Setting max election id to 7fffffff0000000000000001 from replica set primary mongodb-primary:27017 01:40:59.281 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-primary:27017] INFO org.mongodb.driver.cluster - Setting max set version to 1 from replica set primary mongodb-primary:27017 01:40:59.281 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-primary:27017] INFO org.mongodb.driver.cluster - Discovered replica set primary mongodb-primary:27017 01:40:59.293 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-arbiter:27019] INFO org.mongodb.driver.connection - Opened connection [connectionId{localValue:3, serverValue:13}] to mongodb-arbiter:27019 01:40:59.304 [cluster-ClusterId{value='5d558b1b9f1f417c08b4a869', description='null'}-mongodb-arbiter:27019] INFO org.mongodb.driver.cluster - Monitor thread successfully connected to server with description ServerDescription{address=mongodb-arbiter:27019, type=REPLICA_SET_ARBITER, state=CONNECTED, ok=true, version=ServerVersion{versionList=[4, 2, 0]}, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=11086151, setName='replset', canonicalAddress=mongodb-arbiter:27019, hosts=[mongodb-secondary:27018, mongodb-primary:27017], passives=[], arbiters=[mongodb-arbiter:27019], primary='mongodb-primary:27017', tagSet=TagSet{[]}, electionId=null, setVersion=1, lastWriteDate=Fri Aug 16 01:40:50 JST 2019, lastUpdateTimeNanos=133745058351796} 01:41:02.724 [anInnocuousThread] INFO org.mongodb.driver.connection - Opened connection [connectionId{localValue:4, serverValue:24}] to mongodb-primary:27017所感
docker-compose up -dも含めた管理スクリプトを書けば"ポチッとな"と楽ちんになりそうだけど何かピンとこないから保留中. ちゃんちゃん.参考文献
- 投稿日:2019-08-16T01:37:34+09:00
Docker環境でAtomからRubocopを使う方法
この記事なんやねん
最近はDockerを使って環境構築をするケースが多いと思いますが、Atomなどのテキストエディタのコードフォーマットで使うRubocop系のライブラリを動作させるための日本語の記事が意外となかったので投稿します。
Atomのlinter-rubocopをDocker経由で動作させるのを目的に書いていきます。
docker-composeでも動きますよ。手順
ここから早速始めていきましょう。因みに、以下の環境は揃っているという前提で進めます。
- Dockerとdocker-composeをインストール済み
- Atomをインストール済み
- docker-composeを使ってRails環境を構築済み
もし、 環境構築まだやねん って状態だったら、こちらの記事を参考に開発環境を作ってみてください。
また、自分の使ってる
.rubocop.ymlはこちらになります。まだ用意してなければなければ使ってみてください。ラッパースクリプトの配置
まずは、ラッパースクリプトを作成しましょう。
配置場所はどこでもいいですが、プロジェクト配下にbin/rubocopというパスで配置するのが分かりやすいかと思います。今回の例ではそうします。
docker execしていますがdocker runコマンドでも動作します。
ただ、execの方が早いので、コンテナを起動しておいてexecコマンドにてrubocopを叩く方が使い勝手がいいかと思います。
ここら辺はお好みで変えてください。bin/rubocop#!/bin/bash CMD_ARGS="" for arg in $@ do if [ -f "$arg" ] then CMD_ARGS="$CMD_ARGS ${arg#$PWD/}" else CMD_ARGS="$CMD_ARGS $arg" fi done docker exec -i <コンテナ名> rubocop $CMD_ARGS
<コンテナ名>にrubocopがインストールされてるコンテナ名を記載してください。docker-compose psコマンドで確認できます。
因みに、私の環境では下記のようにhr_web_1がrailsとrubocopがインストールされてるコンテナになります。% dc ps Name Command State Ports --------------------------------------------------------------- hr_chrome_1 /opt/bin/entry_point.sh Exit 143 hr_db_1 docker-entrypoint.sh postgres Exit 0 hr_web_1 bundle exec rails s -p 300 ... Exit 1記述したら、
chmod +x bin/rubocopで実行権限を付与するのを忘れないでください。スクリプトの実行準備が整ったら、
docker-compose up -dでコンテナを起動しておきましょう。プラグインの設定
linter-rubocopから
Installボタンを押して、プラグインをAtomにインストールしてください。次に、AtomのLinter Rubocopの設定画面から、Command欄に
./bin/rubocopと入力してください。これで設定は終わりです。
まとめ
全てDocker内で完結できるとスッキリしていいですね。
因みに、いくつかRailsプロジェクトを掛け持ちしてると、あるプロジェクトではDocker使ってなくてローカルでRubocop使う場合もありますよね。そんな時はわざわざAtomの設定を変更しなくても、ラッパースクリプトの最後の行のコマンドをこのように変更すれば大丈夫です。
rubocop $CMD_ARGSはい、単純にローカルにインストールした
rubocopを実行してるだけですね。それではDockerと過ごすRubocopライフを楽しんでください。
- 投稿日:2019-08-16T00:14:10+09:00
vuejsでsuggestフォームを作る1
suggestフォームパッケージを作ってみようと思います
vuejs,Elasticsearchを使っていく予定。npmパッケージ化を目指します第1回目はDockerにVue.jsの環境をつくるところまで
やりたいこと
キーワードを入力していくとキーワード候補エリア、関連エリア(もしかして、、、これ?みたいな)が表示されるやつを作ります
#既に、こんな素敵なパッケージがあるのでそれを使えばこの話はお終いなんですけど。作りたいのでいいのです
vue-simple-suggestではまずにDockerで環境を作っていきます
Vue.js環境作成
1.Dockerfileを作成
DockerfileFROM node:12.8.0-alpine WORKDIR /app RUN apk update && \ npm install -g npm vue-cli EXPOSE 9000 CMD ["/bin/sh"]2.docker-compose.yamlを作成
docker-compose.yamlversion: '3' services: vue_app: build: . ports: - 9000:9000 volumes: - .:/app command: /bin/sh3.Makefileを作成
MakefilePROJECT = vueSearchSuggest .PHONY: start start: docker-compose -p $(PROJECT) up -d --build .PHONY: logs logs: docker-compose -p $(PROJECT) logs -f .PHONY: restart restart: docker-compose -p $(PROJECT) kill && \ docker-compose -p $(PROJECT) rm -f && \ docker-compose -p $(PROJECT) up -d --build .PHONY: kill kill: docker-compose -p $(PROJECT) kill .PHONY: ps ps: docker-compose -p $(PROJECT) ps4.起動
$ make start5.Vue.jsのコンテナに入る
プロセス確認
$ make ps docker-compose -p vueSearchSuggest ps -a Name Command State Ports ------------------------------------------------------------------------------------------ vuesearchsuggest_vue_app_1 docker-entrypoint.sh /bin/sh Up 0.0.0.0:9000->9000/tcp起動中のコンテナに入る
$ docker exec -it vuesearchsuggest_vue_app_1 sh6.Vue.jsのインストール
/app # vue init webpack /app # npm install9000ポート起動に変更
config/index.js16 // host: 'localhost', // can be overwritten by process.env.HOST 17 // port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 host: '0.0.0.0', // can be overwritten by process.env.HOST 19 port: 9000, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined6.Vue.jsのインストール
/app # npm run devhttp://localhost:9000/
を開いて動作確認次回はElasticsearchの環境を作っていきます


































