- 投稿日:2019-12-01T22:10:43+09:00
ExmentのDocker環境を作ってみた
概要
ちょっとしたWeb用DBを作る場合、Exmentが便利そうだったので、気軽に試験できる使えるDocker環境を作ってみました。
使い方
定義ファイル取得
以下gitにcomposeを作成しました。
同ファイルをダウンロードします。コンテナ起動
取得してきたパスで以下コマンドを実行してコンテナを起動します。
docker-compose up
初期設定
コンテナが起動すると以下パスに各種ページが起動しています。
パス 機能 http://localhost:8080/admin Exmentインストールページ http://localhost:8888 phpMyAdmin Exmentの初期設定を行うため「http://localhost:8080/admin 」へ接続します。
接続する以下のような画面が表示されるめたそのまま「Submit」します。次にSQLの初期設定画面が表示されるます。
各項目に関して、以下表のように設定し「送信」を押します。
項目 設定値 ホスト名 db データベース名 exment_database ユーザー名 exment_user パスワード secret 以下画面が表示されるので「インストール実行」を押します。
しばらくすると「Exment初期設定」画面が表示される。ここまで表示されれば環境構築は問題なく実行できている。あとはサイトの設定を行えばExmentが使用できる状態となります。
その他
この設定ファイルはExmentのお試し用に作りました。
セキュリティに関して十分に検討して作っていないため、本番適応する場合はセキュリティ面など再度検討してから使って下さい。やり残し
本当は環境変数を指定してExmentのインストールバージョンを指定できるようにしようと思いました。
しかし、gitで落ちてくるファイルだと何らかのビルドを通さないと実行可能な状態にならなくて、ビルド方法が不明だったため、バージョン指定できる状態になっていません。
参考
- 投稿日:2019-12-01T22:09:48+09:00
PHP7.4が出たので、すぐに使えるLAMP環境をdocker-compose形式で作成しました
Qiitaでポエムが増えてるので、自分もいいだろうと思って投稿。
どういう記事?
PHP7.4がでた。
CentOS8も出てた。
MySQL8も(結構前に)出てた。じゃあ、自分の作業環境ほしいよね?
作るか。コンセプトは、最低限の環境がすぐ使える!
答えだけくれ!な人へ
- LAMP_environment_by_docker-compose をクローン
docker-compose up -d --build
- アクセス
- docker for windowsの場合: localhost:8080
- docker tool box の場合: 多分
192.168.99.102:8080
。docker-machine ip
で出てくるIP使って- MacとLinuxは知らん。動作確認したらREADMEのプルリクください。
苦労した点
- PHP7.4からなんかリポジトリ変わってた
- CentOS8はyumじゃなくなってた。dnfだった。
- でもyumも使える(リンクはられてた)
- すでに用意されてるイメージは甘え。自分でDockerfile書くぞ!
- MySQLは、パスワード系がめんどかったので甘えた。
使い方
- Dockerインストールしてね
- LAMP_environment_by_docker-composeをクローンしてね
docker-compose up -d --build
叩いてね- htdocsフォルダにPHPとかおいてね
- localhostにアクセスしてね。ポートは
8080
- なんか拡張したり間違ってたら遠慮なくプルリク送ってね
- 投稿日:2019-12-01T21:54:13+09:00
ローカルでcircleciコマンドを実行したとき、"git: not found"と表示され、エラーとなる
概要
ローカルで
circleci build
コマンドを使って設定ファイルを確認しようとしたところ、エラーでタスクが正常終了しない。console====>> Checkout code #!/bin/sh -eo pipefail mkdir -p /root/project && cd /tmp/_circleci_local_build_repo && git ls-files | tar -T - -c | tar -x -C /root/project && cp -a /tmp/_circleci_local_build_repo/.git /root/project /bin/sh: git: not found tar: empty archive tar: short read Error: Exited with code 1 Step failed Error: runner failed (exited with 101) Task failed Error: task failed実行したconfig.ymlは下記の通り。
config.ymlversion: 2 jobs: build: docker: - image: node:12.13.0-alpine steps: - checkout - run: name: Greeting command: echo Hello, world. - run: name: Print the Current Time command: date原因
コンソールにも出力されているように、checkout時、コンテナ上でgitが実行できないことが原因。
今回使用しているimage:node:12.13.0-alpine
には
gitはデフォルトでは入っていない。対応
checkout実行前に、apkコマンドでgitを用意してあげる。
config.ymlversion: 2 jobs: build: docker: - image: node:12.13.0-alpine steps: - run: name: add git command: apk -U add git - checkout - run: name: Greeting command: echo Hello, world. - run: name: Print the Current Time command: date実行結果は以下の通り
console====>> Checkout code #!/bin/sh -eo pipefail mkdir -p /root/project && cd /tmp/_circleci_local_build_repo && git ls-files | tar -T - -c | tar -x -C /root/project && cp -a /tmp/_circleci_local_build_repo/.git /root/project ====>> Greeting #!/bin/sh -eo pipefail echo Hello, world. Hello, world. ====>> Print the Current Time #!/bin/sh -eo pipefail date Sun Dec 1 12:48:31 UTC 2019 Success!無事、実行されました。
- 投稿日:2019-12-01T20:56:42+09:00
CUDAが動く Julia の深層学習フレームワーク Flux.jl の環境構築をDockerで行う.
本日は
- Julia製の深層学習フレームワーク Flux.jl のアドベントカレンダー1日目の記事として執筆したものです.
Flux.jl Advent Calendar 2019 を作成しました。#Julia言語 #Qiita https://t.co/BLsZ7asCgB
— abap?(ᐡ ᐧ ﻌ ᐧ ᐡ) (@abap34) December 1, 2019
- Flux.jl ってみんな使ってるのかな? 空いてるところは abap 先輩が書くと信じて1日目は環境構築の方法を紹介します.
- ちなみに アドベントカレンダー参加方法はこちらを見るとやり方がわかります
- Julia全般のアドベントカレンダーは別個にあるらしいので我こそはーと思う方は是非書いてくださいな.
一年前を振り返る(ポエム)
- 私が Flux.jl を知ることになったのは1年前なんですが,レイヤーがCPUで動くんだけれどGPUで動かなかったりつらぽよ感がありましたが BatchNormレイヤーがGPUで動くようになったみたいなのでこれから始める方はそこまでストレスなくいけるんじゃないかなーと思います .
- まぁ,まだバージョンが0.10らしいのでこれからですよ.これから.
本題
- 環境構築をDockerで行うことを考えます.かつ NVIDIA の GPU が動く環境を構築しましょう.
- Dockerで. 「Docker CUDA」という言葉でぐぐると nvidia-docker っていう言葉/コマンドが出てくると思いますが, NVIDIA Docker って今どうなってるの? (19.11版) にもあるように名前がコロコロ変わって,NVIDIA Container Toolkit という名前になってるようです.(まぁ nvidia docker って言葉がけっこうシミわかってるので通じると思います)
- まっさらなホスト環境(これからDockerを入れていこうというマシーン環境を指す.ここでは NVIDIAの GPU 付きUbuntuマシーンを想定)から環境構築を始めるときは 同記事のセクション Docker 19.03 以降の環境で前だけを見て生きる場合に従えばOKです.つまり
- ホスト環境にNVIDIAのドライバーを入れる
- Dockerを入れる
- https://github.com/NVIDIA/nvidia-docker から導入
というステップを踏めばOKです.
Dockerfile
- nvidia/cuda の DockerHub を探して適当なtagを探します.ここでは
10.0-cudnn7-devel-ubuntu18.04
としておきます.ドライバーが古いと怒られてしまう可能性があるのでnvidia-smi
などを見て対応するCUDAバージョンを確認するかかくじバージョンアップをしてください.FROM nvidia/cuda:10.0-cudnn7-devel-ubuntu18.04 MAINTAINER SATOSHI TERASAKI RUN apt-get update && apt-get install -y \ build-essential \ libatomic1 \ python \ gfortran \ perl \ wget \ m4 \ cmake \ pkg-config \ git ARG JL_VERSION="v1.3.0" ARG WDIR="/root" ARG JL_BUILD_DIR=$WDIR/build WORKDIR $JL_BUILD_DIR RUN echo "\ CXXFLAGS=-D_GLIBCXX_USE_CXX11_ABI=0\n\ prefix=/usr/local/julia-$JL_VERSION\n\ USE_BINARYBUILDER = 0\n\ " > Make.user \ && cat Make.user \ && git clone --depth=1 -b $JL_VERSION https://github.com/JuliaLang/julia.git julia-$JL_VERSION\ && cp Make.user $JL_BUILD_DIR/julia-$JL_VERSION \ && cd julia-$JL_VERSION \ && make -j $(nproc) \ && make install RUN rm -r $JL_BUILD_DIR ENV PATH=/usr/local/julia-$JL_VERSION/bin:$PATH # runtime test RUN julia -e "using InteractiveUtils; versioninfo()" RUN julia -e 'using Pkg; Pkg.add(["Flux","CuArrays"]); using Flux' CMD ["julia"]
- Juliaを無駄にソースからビルドしてるのは私の趣味なので公式ページのバイナリーのリンクを持ってきてコピーするでいいと思います.
- 例えば docker-library/julia を参照
使い方
ホスト環境にログインして次を実行します.
$ ls Dockerfile $ docker build -t fluxgpu . $ docker run --gpus all --rm -it fluxgpu sudo docker run --gpus all --rm -it fluxgpu _ _ _ _(_)_ | Documentation: https://docs.julialang.org (_) | (_) (_) | _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help. | | | | | | |/ _` | | | | |_| | | | (_| | | Version 1.3.0 (2019-11-26) _/ |\__'_|_|_|\__'_| | |__/ | julia> ; # to jump shell-mode shell> nvidia-smi Sun Dec 1 11:37:39 2019 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 410.48 Driver Version: 410.48 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 GeForce GTX 1080 Off | 00000000:03:00.0 Off | N/A | | 0% 45C P5 19W / 270W | 0MiB / 8119MiB | 0% Default | +-------------------------------+----------------------+----------------------+ | 1 GeForce GTX 1080 Off | 00000000:04:00.0 Off | N/A | | 37% 46C P5 19W / 230W | 0MiB / 8118MiB | 4% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+上記のように
nvidia-smi
コマンドの出力が出ればOKです.一度 REPL モードに戻って次を実行してみましょう:
julia> using Flux julia> d=Dense(100,1000)|>gpu Dense(100, 1000) julia> x=rand(Float32,100)|>gpu; julia> typeof(x) CuArray{Float32,1,Nothing} julia> d(x)|>typeof CuArray{Float32,1,Nothing} julia> d(x) |> size (1000,)
- これは Chainerでいえば
chainer.links.Linear
に相当するレイヤーですね.|> gpu
とすることでDense
レイヤーと データx
をGPUに移しています.- 畳み込みのレイヤーを担当する
Conv
への入力インターフェースは注意が必要です.ChainerですとNCHW
というデータレイアウトを採用していますが.Flux.jlでは逆でWHCN
とすることになります.例えばx=rand(Float32,224,224,3,1)|>gpu
というデータをJuliaでは投げることになります.まとめ
- GPU 付きの環境をDockerで構築し Flux.jl を1年ぶりに動かしました.BatchNorm のforwardが動くのでまともなレイヤーが組めそうですね.
- 今回はとくにFluxのコンテキストはあまりないのでGPGPUをしたい人も各自でカスタマイズして活用できると思います.
- 投稿日:2019-12-01T20:02:12+09:00
ECS Fargateでブランチ毎にQA環境を作れるようにする
目次
前書き
概要
ECSでブランチごとの動作確認用の環境を準備したので、そのノウハウを共有します。
作った環境はこんな感じです。動機
ディレクターが、エンジニアが開発中のブランチの挙動確認をするのに「
git pull
してdocker-compose up
して、メモリが足りなくてビルド終わらなくて…」というのを見て「大変だなー」と思い、パッと動作確認できる環境を作ろうと思いました。本文
利用した主なツール
- aws-cli
- ecs-cli
- docker
- docker-compose
コンテナの構成
fargateで起動するコンテナ群はこんな感じです
コンテナ名 内容 app Nginx+プロダクションコード mysql DB redis バッチジョブ用のキュー 今回は、これを一つのタスクとして起動させています。
docker-compose.ymlで80番ポートを空けてインターネット → nginx → プロダクションコード
という流れで通信が行われます。またfargate特有の事情としては、コンテナ間通信の名前解決がコンテナ名でなくlocalhostとなることなので、それは注意が必要です。
(自分はここで結構ハマりました…)1の解説
現在、ブランチがプッシュされたらCircleCIでphpunitを実行させています。
その工程に、docker imageのビルドとECRへのプッシュを追加します。
実際のコードはこんな感じです。config.yml- run: name: Install Docker client command: | set -x VER="19.03.5" curl -L -o /tmp/docker-$VER.tgz https://download.docker.com/linux/static/stable/x86_64/docker-$VER.tgz tar -xz -C /tmp -f /tmp/docker-$VER.tgz mv /tmp/docker/* /usr/bin - run: name: Install ecs-cli command: | set -x curl -o /usr/bin/ecs-cli https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-linux-amd64-latest chmod +x /usr/bin/ecs-cli - run: name: push docker image to AWS ECR command: | BRANCH_HASH=`echo $CIRCLE_BRANCH | sed 's:/:_:g'`-`git rev-parse HEAD` docker build -f Dockerfile_Ecs -t {{registory_id}}.dkr.ecr.ap-northeast-1.amazonaws.com/{{repository}}:${BRANCH_HASH} . ecs-cli push {{registry_id}}.dkr.ecr.ap-northeast-1.amazonaws.com/{{repository}}:${BRANCH_HASH}ECRの運用としては、一つのレポジトリに対して、「ブランチ名+コミットハッシュ」でタグ付けをしたイメージをプッシュすることにしています。
これでレポジトリにライフサイクルポリシーを設定することで、ECRの容量が肥大化することが防げます。
ただ、イメージのタグに/
が使えないので_
で置換しています。Dockerfile_Ecsの内容としては、ビルド済みのプロダクションコードを
COPY
して、nginxの設定ファイル等を 適切な場所に配置って感じです。2の解説
ユーザーがブランチ名を引数としてスクリプトを実行したら、URLが出力されるようにします。
このURLからECSで起動したサービスにアクセスすることができれば、ユーザーはビルドやgit操作が不要となります。3の解説
今回の肝となるのは、4の
ecs-cli compose --project-name ${branch+hash} service upとなります。
しかし、そのためには入力された、ブランチ名から${branch+hash}
を取得する必要があります。
そのために ECRでイメージ一覧を取得し、ブランチ名の前方一致でフィルターし、そのイメージのタグを取得することで${branch+hash}
を取得します。4の解説
今回で一番重要なのが、この処理となります。
図ではスペースの都合でコマンドを省略しましたが、省略しないと下記になります。BRANCH_HASH=${branch+hash} ecs-cli compose \ -c {{cluster_name}} \ -f docker-compose-ecs-base.yml -f docker-compose-ecs.yml \ --ecs-params docker/ecs/ecs-params.yml \ --project-name ${branch+hash} \ service up \ --launch-type FARGATE環境変数
BRANCH_HASH
に値を渡して、それを下記の docker-compose.yml で取得しています。services: app: build: context: . dockerfile: Dockerfile_Ecs image: "{{registry_id}}.dkr.ecr.ap-northeast-1.amazonaws.com/{{repository}}:${BRANCH_HASH}" ports: - "80:80" command: docker/ecs/entrypoint-app.shこれによって
ecs-cli compose service up
の実行時に、どのタグのイメージをECSで立てるかを決定しています。
ECSはこのコマンドを受けて、タスク定義の作成、ECRからimageの取得、サービス+タスクの起動を行ってくれます。
そして、最後にentrypoint-app.sh
で、migration、シードデータの作成、nginx起動などのコンテナ起動に必要な処理を行っています。5の解説
今回は、4でECSのサービス+タスクがパブリックサブネットで作成されています。
そのため、そのタスクにはパブリックIPが付与されています。
そのパブリックIPをaws ecs describe-tasks
等を利用して取得して、そのIPと${branch+hash}
を紐付けて、 Route53でAレコードを作成します。ユーザーは、このAコードのURLを使うことで、ECSのサービスにアクセスできるようになります。
(パブリックIPが自動的に変更されて、URLとIPの紐付けが変わる可能性が高いような気はしますが、サービスは毎晩に削除しようと思ってるので、まぁ大丈夫かな?という予想です)
終わりに
続きの作業としては
- slackopsにする
- ECSのサービスを自動的に削除する
- Route53のレコードを自動的に削除する
をやりたいなーと思います。
ただslackops対応が意外と難しい…
参考
下記を参考にさせていただきました。
ありがとうございました
- 投稿日:2019-12-01T19:13:44+09:00
Docker + Flask(Python) + Jupyter notebookによる仮想環境構築
毎回構築の方法を忘れるため、備忘録として。
ファイル構成
project L DockerfileDockerfile
javaを利用するライブラリをインストールする可能性があるので、default-jdkを追加しています。
DockerfileFROM python:3.6 RUN apt-get update && apt-get install -y \ default-jdk \ build-essential \ gfortran \ libblas-dev \ liblapack-dev \ libxft-dev \ swig \ && rm -rf /var/lib/apt/lists/* RUN echo 'export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH"' >> ~/.bash_profile && \ . ~/.bash_profile && \ cd ~ &&\ git clone https://github.com/taku910/mecab.git && \ cd mecab/mecab && \ ./configure --enable-utf8-only && \ make && \ make check && \ make install && \ cd ../mecab-ipadic && \ ./configure --with-charset=utf8 && \ make && \ make install &&\ cd ~ &&\ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git && \ cd mecab-ipadic-neologd && \ ./bin/install-mecab-ipadic-neologd -n -y RUN pip3 install --upgrade pyzmq --install-option="--zmq=bundled" && \ pip3 install --upgrade jupyter && \ pip3 install --upgrade \ pandas \ neologdn \ Flask \ numpy \ Pillow \ tensorflow \ ENV LD_LIBRARY_PATH "/usr/local/lib:$LD_LIBRARY_PATH" VOLUME /notebook WORKDIR /notebook EXPOSE 8888 ENTRYPOINT jupyter notebook --ip=0.0.0.0 --allow-root --no-browserDocker imageの作成
Dockerfileのディレクトリに移動して、docker buildコマンドを実行。構築に数分かかります。
$ cd project $ docker build -t image_name --force-rm=true . # (-t イメージ名) イメージ名を自分で決定 # (--force-rm=true) イメージのビルドに失敗したら、イメージを自動で削除するDocker containerの作成
描きコマンドを実行すると、自動でJupyter notebookが起動するので、表示されたURLにアクセスするとJupyter notebookが利用できる。
# 上と同じディレクトリで下記コマンド実行 $ docker run -v `pwd`:/notebook -p 8888:8888 -p 5000:5000 -it --name container_name image_id /bin/bash # http://127.0.0.0:8888/?token=#################### # こんな感じのアドレスが出てくるため、tokenごとコピペする。追加のライブラリをインストール
Jupyter notebookで作業している時に、足りないライブラリをインストールしたい場合は、コンテナの外から、下のコマンドでコンテナの中に入る。
$ cd project $ docker exec -it container_name /bin/bash # 上記コマンドでコンテナ内に入ると、ターミナルが下のように切り替わる。 root@ユーザー名:/notebook# ここにコマンドを入力できるようになる。 # インストールの例 root@ユーザー名:/notebook# pip install numpy
- 投稿日:2019-12-01T17:51:03+09:00
ぼくのかんがえたさいきょうのAPIドキュメント運用
ドキュメントちゃんと保守できてますか?
API開発とドキュメントの保守は切っても切れない問題です。
仕様の記述はもちろんのこと、サンプルを試せるAPIクライアントや、仕様に則った実装になっているかテストも自動化したいですよね。
本記事では、現在開発中のAPIアプリケーションで、実際に僕が試行錯誤していく中でたどり着いたベストプラクティスを紹介しようと思います。
アーキテクチャ
- iOSアプリのバックエンドとしてJSONを返すAPIサーバー
- Rails6 × MySQL5.7 on Docker
いつもの というお買い物アプリです。
ドキュメント何で書いてますか?
- Excel => つらい
- Markdown => つらい
- 何らかのDSLを用いて生成するツール =>
素でマークダウンを書くのはつらみが深いので何かしらツールを使いましょう。
apiary, api blueprint, APIDOC, etc.
いろいろありますが、僕が激しくおすすめするのは OpenAPI です。理由としては、
- Linux Foundation、Google、IBM、Microsoftなどが協力して仕様の策定に関わっていること
- 歴史が長く周辺ツールが豊富で、拡張性があること
- 表現力豊かな記述方法
が挙げられます。
Swagger? OpenAPI?
もともと Swagger という名前だったものが、 OpenAPIと名前を変えてバージョン3.0がリリースされました。
Swaggerと聞けば馴染みのある方も多いと思います。
基本的にSwaggerとOpenAPIを読み替えても問題はないのですが、(ドメインとか残ってるし => https://swagger.io/specification/)
Swaggerは2.xまでで、OpenAPIは3.0からになるので、Swaggerのバージョン3というものは厳密には存在しません。OpenAPIが優れている理由
使ったことがない人向けに説明をしておくと、
OpenAPI とは、RESTful API を記述するためのフォーマットの標準であり、
その標準を用いて様々なことを解決するためのヘルパーツール群を提供するものです。ツールは大きく3種類に分けられます。
- Swagger Codegen
- スタブサーバーとクライアントSDKの生成
- Swagger Editor
- 定義ファイルの編集が行えるリッチエディタ
- シンタックスのチェックや補完、ホットリロードでのプレビューをサポート
- Swagger UI
- HTMLとしてドキュメントをビジュアライズする
- 定義されたホストに対してリクエストを送信するAPIクライアントとしても使用できる(Postman的な)
この3つのオープンソースツールを拡張する形で、各言語ごとのラッパーやフレームワークへの組み込みをサポートするライブラリが数多く作成されています。(ex. swagger-blocks)
自分が実現したいことに合わせて柔軟にモジュールを組み込むことができるので、どのプロジェクトにも導入がしやすいです。
また、先に述べたように、OpenAPI とはただ単にフォーマットを標準化した
仕様
なので、
ツールを通さなくてもその仕様に則って記述した yaml ファイルをただ共有するだけみたいな使い方もできます。
yamlさえあれば、受け取った人は何かのツールを使って自由に拡張利用できるので、非常にポータビリティが高いと言えます。Dockerファイルで環境のやりとりするみたいなイメージに近いそして錚々たる大企業たちがスポンサーとなっているため、業界の標準となっていくことは確実です。
OpenAPIの記述に慣れておくことは、エンジニアとして必要なスキルになってくるかと思っています。実際に使ってみよう
今回実現したいことはこちらです。
- ドキュメントをブラウザで手軽に確認したい
- ドキュメントを楽に記述したい
- ドキュメントをローカルサーバーのHTTPクライアントとして使いたい
- レスポンスがドキュメントに則っているか自動テストしたい
これ全てOpenAPIでできます。
ただ実際にやろうとするとツールが豊富で選択肢が多い割に、3.0に対応していないものが多かったり、情報がまとまっていなかったり、ベストプラクティスにたどり着くまでに苦労したので、この記事が何かの助けになれば幸いです。
ちなみにですが、2.xと3.xでは破壊的な変更があるので、2系のツールで3系を動かすのは無理があります。
多くのツールで3に対応するissueが上がっているのですが、長い間放置されているものが多いため、3を使おうとすると選択肢は結構狭まります。ドキュメントをブラウザで手軽に確認したい
まずはサンプルとなるエンドポイントを実装します。
config/routes.rbRails.application.routes.draw do resources :users endapp/controllers/users_controller.rbclass UsersController < ApplicationController def index user = { :name => "sakuraya", :age => 26 } render :json => user end end$ curl localhost:3000/users {"name":"sakuraya","age":26}これを OpenAPI のドキュメントとして記述します。
yaml と json がサポートされていますが、特に理由がなければ yaml を使うことをお勧めします。ファイル名は何でもいいんですが、
openapi.yml
がスタンダードです。doc/openapi.ymlopenapi: 3.0.2 info: title: "ぼくのかんがえたさいきょうのAPIドキュメント運用" description: "サンプルアプリ" version: "1.0.0" tags: - name: "users" description: "ユーザーAPI" paths: /users: get: summary: "ユーザーを取得" description: "ユーザーを取得" tags: - "users" responses: 200: description: "成功時" content: application/json: schema: type: "object" properties: name: description: "名前" type: "string" example: "sakuraya" age: description: "年齢" type: "integer" example: 26 required: - "name" - "age"最低限これだけ書けばOKです。
これをブラウザで見るためには、SwaggerUIというツールを使います。
SwaggerUIで調べると Node.js を使ってサーバーを立ち上げる例ばかりが出てきますが、
別で立てるのは面倒なので docker-compose で一緒に立ち上げてしまいます。
イメージが公開されているのでこれをベースにします。docker-compose.ymlversion: '3' services: web: &app_base build: context: . ports: - 3000:3000 command: bundle exec rails s -p 3000 -b 0.0.0.0 volumes: - .:/myapp - bundle:/usr/local/bundle depends_on: - db db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: password TZ: Asia/Tokyo command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci volumes: - ./vendor/docker/db/data:/var/lib/mysql - ./vendor/docker/db/conf.d:/etc/mysql/conf.d - ./vendor/docker/db/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d ports: - 3306:3306 doc: image: swaggerapi/swagger-ui volumes: - ./doc/openapi.yml:/usr/share/nginx/html/openapi.yml environment: API_URL: openapi.yml ports: - 8080:8080 volumes: bundle:
doc
の部分が SwaggerUI です。
doc
配下に置いたドキュメントファイルをマウントして、ファイル名を環境変数で指定することで、ドキュメントサーバーが立ち上がるようになっています。
これで http://localhost:8080 にアクセスすると、インタラクティブなUIでドキュメントが表示されます。▼それぞれ対応するセクションがこうなっている。
▼パスをクリックするとアコーディオンが開いて仕様が表示される。
▼上の画像は
Example Value
を表示したもので、Schema
をクリックすると、プロパティの説明、型、requiredの有無、nullableの有無など詳細が表示される。ドキュメントサーバーとAPIサーバーの立ち上げをいっぺんに管理できるのが便利
ドキュメントを楽に記述したい
エディタごとにプラグインがそれぞれあるかと思います。
僕は普段 VS Code を使っているのでこれを入れています。あとはプレビュー用として Swagger Viewer を入れておいてもいいかと思います。
ホットリロードで確認しながらできるので便利です。
一つだけ注意点があって、たまに表示がおかしくなったり、正しく表示されないことがあります($ref
が展開されないなど)。
なので僕は書き方に慣れるまではこれを使っていましたが、いまはブラウザでまとめてチェックしています。あとは書き方のTipsですが、
components
を使って共通化していくと見通しが良くなります。doc/openapi.umlpaths: /users: get: summary: "ユーザーを取得" description: "ユーザーを取得" tags: - "users" responses: 200: description: "成功時" content: application/json: schema: $ref: "#/components/schemas/User" components: schemas: User: description: "ユーザー" type: "object" properties: name: description: "名前" type: "string" example: "sakuraya" age: description: "年齢" type: "integer" example: 26 required: - "name" - "age"ドキュメントをローカルサーバーのHTTPクライアントとして使いたい
せっかく docker-compose してるんだから、ローカルのサーバーに実際につないで動かしたいですよね?
API開発時のHTTPクライアントにはずっと Postman や、
最近だと REST Client なんかを使っていましたが、ドキュメントの変更に対する反映が面倒だったりするのが難点です。
OpenAPIを組み込めればそんな手間もなくなります。SwaggerUI には
Try it out
というボタンがついています。
このままでは利用できないので設定を行います。
servers
というセクションを追記してください。doc/openapi.ymlservers: - url: "http://localhost:3000" description: "local api server"これがボタンを押した時のリクエスト先のベースURLとなります。
▼トップに
servers
の設定が反映されました。複数設定することができ、切り替えられるようになっています。▼ボタンを押すとパラメータが編集できるようになり、
Execute
ボタンが現れます。
(今回はパラメータないが適当に書くとこんな感じ。よしなにクエリパラメータに突っ込んでくれる。)もう一つ設定が必要で、このままリクエストを送ってもこのようなエラーが出ます。
Access to fetch at 'http://localhost:3000/users?some_condition=true' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.Access to fetch at 'http://localhost:3000/users?some_condition=true' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Cross Origin の制約を回避するために、Rails側に設定が必要です。
rack-cors という gem を使います。
ドキュメントサーバーを使うのは開発環境だけなので、development.rb
に記述します。config/environments/development.rbconfig.middleware.insert_before 0, Rack::Cors do allow do origins "localhost:8080" resource "*", :headers => :any, :methods => :any end endこれでサーバーを再起動すれば、リクエストできるようになります。
▼生成されたcurlコマンドと、レスポンスが表示されました。
いちいち Postman 開いてリクエスト書く必要がないので幸せ
レスポンスがドキュメントに沿っているか自動テストしたい
これだけでもだいぶ開発が捗るようになったんですが、テストまでいきたいです。
ドキュメントで Integer になってるプロパティが String で返ってきたり、
required なプロパティがレスポンスになかったら落ちるようにしたいですよね。rspecに組み込んでみます。
Gemfilegem 'rspec-rails'docker-compose run web bundle docker-compose run web rails generate rspec:installspec/requests/users_spec.rbrequire "rails_helper" RSpec.describe UsersController, :type => :request do describe "#index" do let(:path) { users_path } it do get path expect(JSON.parse(response.body)).to match( # いい感じにドキュメントのスキーマを検証したい ) end end endcommittee という gem を使います。
さらにそれを Rails 用にラップした committee-rails も使います。Gemfilegem 'committee' gem 'committee-rails'設定を追加。
spec/rails_helper.rbconfig.add_setting :committee_options config.committee_options = { :schema_path => Rails.root.join("doc", "openapi.yml").to_s } include ::Committee::Rails::Test::Methodsテストを落とすために、 Integer であるはずの年齢を String に書き換えます。
app/controllers/users_controller.rbclass UsersController < ApplicationController def index user = { :name => "sakuraya", :age => "26" } render :json => user end endテストをこう書きます。
spec/requests/users_spec.rbrequire "rails_helper" RSpec.describe UsersController, :type => :request do describe "#index" do let(:path) { users_path } it do get path assert_request_schema_confirm assert_response_schema_confirm end end end実行すると。。。
F Failures: 1) UsersController#index Failure/Error: assert_response_schema_confirm Committee::InvalidResponse: #/components/schemas/User/properties/age expected integer, but received String: 26 # /usr/local/bundle/gems/committee-3.3.0/lib/committee/schema_validator/open_api_3/operation_wrapper.rb:35:in `rescue in validate_response_params' # /usr/local/bundle/gems/committee-3.3.0/lib/committee/schema_validator/open_api_3/operation_wrapper.rb:30:in `validate_response_params' # /usr/local/bundle/gems/committee-3.3.0/lib/committee/schema_validator/open_api_3/response_validator.rb:20:in `call' # /usr/local/bundle/gems/committee-3.3.0/lib/committee/schema_validator/open_api_3.rb:38:in `response_validate' # /usr/local/bundle/gems/committee-3.3.0/lib/committee/test/methods.rb:27:in `assert_response_schema_confirm' # ./spec/requests/users_spec.rb:9:in `block (3 levels) in <top (required)>' # ------------------ # --- Caused by: --- # OpenAPIParser::ValidateError: # #/components/schemas/User/properties/age expected integer, but received String: 26 # /usr/local/bundle/gems/openapi_parser-0.6.1/lib/openapi_parser/schema_validator.rb:62:in `validate_data' Finished in 0.11266 seconds (files took 3.96 seconds to load) 1 example, 1 failure Failed examples: rspec ./spec/requests/users_spec.rb:6 # UsersController#index無事落ちました!
▼requiredな値がないときはこうなったりします。
1) UsersController#index Failure/Error: assert_response_schema_confirm Committee::InvalidResponse: #/components/schemas/User missing required parameters: ageテストまでかけるとか最高か
普段の開発フローとしては、まずドキュメントを記述して仕様をレビュー => テスト書く => 実装というドキュメント&テスト駆動開発でやっています。
まとめ
今回は既存のプロジェクトに後から組み込んだので使ってませんが、
ドキュメントからモックサーバーを立ち上げたり、コードを生成したりするツールも言語ごとにいろいろあります。
うまく活用してAPIドキュメント運用のつらみから解放されましょうOpenAPI の記述方法については、OpenAPI-Specification を見ながら覚えていくのがオススメです。
[追記]
今回使ったサンプルコード
- 投稿日:2019-12-01T17:14:15+09:00
軽量なSambaのDockerイメージを作ってRaspberry Piで動かしてみた
はじめに
Raspberry PiをNASにするため,Dockerでsambaを立ち上げるべく,Alpine Linuxをベースイメージとして,(たぶん)軽量なイメージを作成してみました↓↓
Dockerでsambaを動かす場合はdperson/sambaが有名ですが,今回は勉強もかねてすべて自分でDockerfileを書いてみました.
環境
Raspberry Piで動かします。
- マシン: Raspberry Pi 3B+
- OS: hypriot OS
$ docker --version Docker version 19.03.5, build 633a0eaつくるもの
機能は単純に高望みせず,以下のような物を目指します.
- ユーザのホームディレクトリを共有
- 軽量にするためベースイメージはAlpine Linux
- あくまで個人利用目的で複数ユーザ、セキュリティは考慮しない
つくったもの
構成は、
- Dockerfile
- smb.conf
- start_samba_system.sh
の3ファイルです。
smb.confはbuild時にイメージに取り込まれ、デフォルトのsmb.confと置き換えられます。また、start_samba_system.shはsamba起動スクリプトです.
Dockerfile
FROM alpine:3.9 MAINTAINER HoriThe3rd ENV USERNAME="name" \ PASSWD="weak_passwd" RUN apk update && apk --no-cache add samba COPY ./smb.conf /etc/samba/ COPY ./start_samba_system.sh /usr/local/bin RUN chmod 775 /usr/local/bin/start_samba_system.sh EXPOSE 139 445 ENTRYPOINT [ "/bin/ash" ] CMD [ "/usr/local/bin/start_samba_system.sh" ]コンテナ起動時は、ENTRYPOINTで/bin/ashを呼び出し、CMDでstart_samba_system.shを走らせています.
このシェルスクリプト内で環境変数USERNAMEとPASSWDを使ってsambaユーザを作成し,sambaを起動します.docker run時に環境変数を設定することで任意のユーザ名とパスワードに対応します.なお、Alpine Linuxを用いているので、シェルはbashではなくashが標準です。
samba起動スクリプト
ユーザの作成を行った後にsambaを起動しています.
シェバンが#!/bin/ashになっています.#!/bin/ash # Create an account adduser -D $USERNAME echo $USERNAME':'$PASSWD | chpasswd echo -e $PASSWD'\n'$PASSWD | pdbedit -a -u $USERNAME # Start daemons nmbd restart -D smbd restart -FS </dev/null最後の行の</dev/nullはコンテナを起動した瞬間にexitedとなってしまうのを防ぐために入れています.こちらの記事を参考にさせていただきました.
Dockerでイメージ作成してsamba立ち上げるsmb.conf
ホームディレクトリを共有する設定をしたものを配置しました.
[homes] comment = Home Directories browseable = no writable = yesビルド
Dockerfileのあるディレクトリでビルドします。
docker build -t mysamba:1.0 .ビルド後のimageのサイズは、私の環境で32.1 MBと思いの外軽量に出来あがりました。dockerhubで有名なdperson/sambaが200 MB以上だったので大幅に軽くなっています。
もちろん、今回作成したものは必要最低限の構成なので、この比較はあくまで参考値とお考えください。ラズパイのようなリソースの少ないマシンでは特に小型なのは助かります。
Run
自分でビルドしない場合は,次の"Dockerhubからダウンロードして実行する場合"を使ってください.
コンテナの/home/USERNAME/以下がsambaで共有されるので、-vオプションなどでホストのストレージと同期するようにして起動します。--restart=alwaysで再起動時に起動するようにしています。
docker run -d -p 139:139 -p 445:445 --name smb --restart=always -v <host path>:/home/USERNAME -e USERNAME="<your_name>" -e PASSWD="<your_pw>" mysamba:1.0Dockerhubからダウンロードして実行する場合
Dockerhubにイメージをpushしていますので,以下のコマンドで実行できます.
ラズパイで実行する場合は,rpiタグで使用できます.latestはアーキテクチャがamd64なので通常のマシン用です(試していませんが・・・).docker run -d -p 139:139 -p 445:445 --name smb --restart=always -v <host path>:/home/USERNAME -e USERNAME="<your_name>" -e PASSWD="<your_pw>" horithe3rd/lw_samba:rpiおわりに
実際にDockerfileを手書きしてなかなか勉強になりました.
Alpine Linuxを用いることでかなり軽量なsambaイメージを作成することができました.ラズパイのようにリソースが少ないマシンで扱うにはやはりCentOSやUbuntuをベースにすると重たくなってしまうのでAlpine Linuxが便利ですね.
なお,今回作成したイメージはセキュリティなどは全く考えていないので,何かあっても作者は責任は取らないことはお約束です・・・
- 投稿日:2019-12-01T17:04:20+09:00
Docker + Wordpress 環境構築(Mac)
概要
wordpressの環境をdockerで用意する方法をまとめていきます。
前提
- mysql 5.7
- Docker for Mac 無ければDockerの公式からインストール
コンテナ作成
それではdocker-compose.ymlでコンテナを作成していきます。
適当にディレクトリを用意してdocker-compose.ymlファイル作成
$ mkdir docker $ cd docker $ vim docker-compose.ymldocker-compose.ymlファイルを下記のように記述
docker-compose.ymlversion: '3.3' services: db: image: mysql:5.7 ports: - "3306:3306" volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: image: wordpress:latest depends_on: - db ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress volumes: - ./wordpress:/var/www/html volumes: db_data:Sequel ProでDBに接続したいので今回はmysql5.7系でインストールします。8.0系はSequel Proのバージョンによって動かないことがあるので対策が必要です(下記リンクを参考)
MySQL8.0.x に Sequel Pro で接続する
MySQL8.0でSequel Proを使えるようにするまたSequel Proに接続するためにpostsを追記していますが
ports: - "3306:3306"3306が既にlocalでmysqlが起動している場合があるので、3306以外を使う必要があります。
volumes: - ./wordpress:/var/www/html上記はDockerのバインド・マウントを利用して、./wordpress(ホスト側のディレクトリ)と/var/www/html以下のwordpressのファイル群(コンテナ側のディレクトリ)を接続しアクセスできるようにします。
このバインド・マウントによりホスト側のwordpressのファイルを編集するとコンテナ側にも反映させることができます。
参考:
https://qiita.com/mom0tomo/items/7e611ac829863d4c5c82docker-compose.ymlを作成したディレクトリ内でコンテナの作成と起動
$ docker-compose up -dコンテナが生成されているか確認
$ docker-compose psName Command State Ports ------------------------------------------------------------------------------ docker_db_1 docker-entrypoint.sh Up 0.0.0.0:3306->3306/tcp, mysqld 33060/tcp docker_wordpress_1 docker-entrypoint.sh Up 0.0.0.0:8000->80/tcp apach ...生成、起動されているのでブラウザからhttp://localhost:8000/アクセスすると...
wordpressの画面が見れました。
Sequel Proで接続
最後にDB管理ツールのSequel Proでmysqlコンテナに接続していきます。
docker-compose.ymlのDBの情報を入力して接続すると成功しデフォルトでテーブルがいくつか確認できます。
最後に
今回は以上です。
自分用のwordpressの環境が整ったので何か作成していきます。
ありがとうございました。参考
https://qiita.com/mom0tomo/items/7e611ac829863d4c5c82
https://qiita.com/ucan-lab/items/b68db1db931c954da921
- 投稿日:2019-12-01T16:32:33+09:00
Docker+Laravel+OpenAPIGenerator
はじめに
OpenAPIGeneratorを使って生成されたLaravelのソースコードで環境構築してみました。
DockerでLaravel環境の構築~スタブサーバの生成、リクエストの確認まで行います。プロジェクトディレクトリ構成
project/ ├ www/ # Laravel Project Container ├ generator/ # generator Container ├ docker-compose.yml ├ oas.ymlSample OAS
プロジェクト直下に
oas.yml
を用意します。
簡易的なCRUDが行えるAPIを想定しています。oas.ymlopenapi: 3.0.0 info: title: Task API version: 0.0.1 servers: - url: http://localhost description: Laravel Server tags: - name: Task paths: /api/task: get: tags: [ "Task" ] summary: Show Task List. description: Show Task List. operationId: listTask responses: '200': description: Successful response post: tags: [ "Task" ] summary: Create Task One operationId: createTask requestBody: content: application/x-www-form-urlencoded: schema: type: object properties: title: type: string sort: type: integer responses: '200': description: Successful response /api/task/{tid}: get: tags: [ "Task" ] summary: Show Task One. description: Show Task One. operationId: showTask parameters: - name: tid in: path required: true schema: type: string responses: '200': description: Successful response put: tags: [ "Task" ] summary: Update Task One. operationId: updateTask description: Update Task One. parameters: - name: tid in: path required: true schema: type: string requestBody: content: application/x-www-form-urlencoded: schema: type: object properties: title: type: string sort: type: integer responses: '200': description: Successful response delete: tags: [ "Task" ] summary: Delete Task One. operationId: deleteTask description: Delete Task One. parameters: - name: tid in: path required: true schema: type: string responses: '200': description: Successful responseDocker環境を用意する
docker-compose.yml
をproject直下に用意します。docker-compose.ymlversion: '3.4' services: generator: build: ./generator volumes: - .:/app tty: true command: sh www: build: ./www volumes: - ./www:/var/www ports: - 80:80
generator
コンテナはOASからPHPコードを生成するコンテナになります。
www
コンテナはApacheで動作するLaravel環境のコンテナになります。続いて、
generator
コンテナを構築するためのDockerfileをgenerator/
配下に用意します。FROM openjdk:8-jdk-alpine WORKDIR /app RUN apk --update add bash maven git RUN rm -rf /var/cache/apk/*ls RUN git clone https://github.com/openapitools/openapi-generator /generator RUN cd /generator && mvn clean packageOpenAPIGeneratorはJVMでありJava環境が必要なため
openjdk:8-jdk-alpine
をベースにしています。
ライブラリのインストーラとしてmaven
を使用します。続いて、
www
コンテナを構築するためのDockerfileをwww/
配下に用意します。FROM php:7.3-apache RUN apt-get update && apt-get install -y git libzip-dev libxml2-dev RUN docker-php-ext-configure zip --with-libzip RUN docker-php-ext-install pdo_mysql mbstring zip xml RUN curl -sS https://getcomposer.org/installer | php RUN mv composer.phar /usr/local/bin/composer RUN a2enmod rewrite && a2enmod headers RUN sed -ri -e 's!/var/www/html!/var/www/public!g' /etc/apache2/sites-available/*.conf RUN sed -ri -e 's!/var/www/!/var/www/public!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf RUN usermod -u 1000 www-data && groupmod -g 1000 www-data ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin WORKDIR /var/www RUN composer global require "laravel/installer"今回はApache上で動作するPHP(
php:7.3-apache
)をベースにしています。
Laravelを使いたいのでcomposer
をインストールしています。
URLを書き換えやリダイレクトを有効にするため、a2enmod rewrite && a2enmod headers
を実行しています。
sed
でLaravel用のドキュメントルートに変更しています。
Apacheを動かすwww-data
ユーザがLaravelから吐き出されるlogファイルにアクセスできるように権限を付与しています。上記の準備ができたらコンテナを起動します。
各リソースのDLやInstall処理が一気に走るため結構な時間を要するかと思います。$ docker-compose up -d --buildLaravel用のソースコードを自動生成する
OpenAPIGeneratorを使用してソースコードを生成します。
generator
コンテナに入って作業します。$ docker-compose exec generator bash bash-4.4# java -jar /generator/modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \ -i oas.yml \ -g php-laravel \ -o server-generate bash-4.4# cp -rf server-generate/lib/. www上記を実行すると、
server-generate
に自動生成されたPHPのソースコードが出来上がると思います。
生成されたソースコード一式はwww
コンテナへコピーします。
ちなみに、自動生成できるコードの種類はこちらから確認できます。生成されたソースコードからLaravel環境を立ち上げる
$ docker-compose exec www bash root@5295f267d6a1:/var/www# composer install root@5295f267d6a1:/var/www# cp .env.example .env root@5295f267d6a1:/var/www# php artisan key:generate上記の実行が済めば、http://localhost にアクセスして下記の画面を確認することができると思います。
続いて、生成されたコードが機能しているのか確認してみます。
php artisan route:list
を実行してAPIのエンドポイントを確認してみます。$ docker-compose exec www bash root@5295f267d6a1:/var/www# php artisan route:list +--------+----------+----------------+------+------------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+----------------+------+------------------------------------------------+------------+ | | GET|HEAD | / | | App\Http\Controllers\Controller@welcome | web | | | POST | api/task | | App\Http\Controllers\TaskController@createTask | api | | | GET|HEAD | api/task | | App\Http\Controllers\TaskController@listTask | api | | | DELETE | api/task/{tid} | | App\Http\Controllers\TaskController@deleteTask | api | | | GET|HEAD | api/task/{tid} | | App\Http\Controllers\TaskController@showTask | api | | | PUT | api/task/{tid} | | App\Http\Controllers\TaskController@updateTask | api | +--------+----------+----------------+------+------------------------------------------------+------------+エンドポイントの確認が行えたので、続いてswagger-editorからGETリクエストを試したいと思います。
ただ、現時点のままだとCORSに引っかかりリクエストできません。
そのため、リクエストのテストを行う前にCORS対策を行います。
まずはbarryvdh/laravel-cors
をインストールします。$ docker-compose exec www bash root@5295f267d6a1:/var/www# composer require barryvdh/laravel-cors
www\config\app.php
に下記を追加します。'providers' => [ // ... Barryvdh\Cors\ServiceProvider::class, ]
app/Http/Kernel.php
に下記を追加します。'api' => [ // ... \Barryvdh\Cors\HandleCors::class, ],設定ファイルを以下のコマンドで作成します。
root@02eec0e47db9:/var/www# php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"設定が完了したので、swagger-editorでリクエストテストを行ってみます。
無事にGETリクエスト出来たことを確認しました。以上、Laravel用のスタブサーバの生成および構築までの流れでした。
自動生成されたコードはスタブなため、実処理は開発者が実装していくことになります。
何かの参考になれば幸いです。
- 投稿日:2019-12-01T16:00:14+09:00
DockerをWindowsノートPCで触ってみた
会社でGCPを使っていて、いろいろ勉強しなければなりません。恥ずかしい内容ですが、備忘録として残しておきます。将来、GCPでデータ処理、データ蓄積をしたいなー、とも思っています。自宅でWindowsノートPCでTutorial 動かしました。
Windowsの設定: Hyper-V をONにする
- 「Windowsの機能の有効化または無効化」で Hyper-V をONにして、再起動する。
- 「Windows 管理ツール」から「Hyper-V マネージャー」を起動してみる。(今回は関係ないですが、仮想マシンはまだ何もありません。)
Docker Desktop for Windows を使ってみる。
Docker Hubで登録してからダウンロード。
Downlaod Docker Desktop for Windows のボタンを押して指示に従っただけですが、CUIのdockerのツール一式がインストールされたようです。以下はtutorial をフォローしただけ。Power Shell で動かしました。
git clone https://github.com/docker/doodle.git./doodle/cheers2019 というディレクトリで、build して、ローカルで動かします。build してできるものはイメージと呼ばれるようです。ソースコードはGO lang で書かれていました。xxxxxはIDで、-t <イメージ名> です。
> docker build -t xxxxx/cheers2019 .build する/イメージを作る(docker build)
build の設定は、同じディレクトリにあるDockerfile に書かれているものが読まれます。読んでもよく分かりません。
FROM golang:1.11-alpine AS builder RUN apk add --no-cache git RUN go get github.com/pdevine/go-asciisprite WORKDIR /project COPY cheers.go . RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o cheers cheers.go FROM scratch COPY --from=builder /project/cheers /cheers ENTRYPOINT ["/cheers"]ローカルで動かす (docker run)
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run a command in a new containerローカルで動かします。-i はコンテナの標準入力、-tはtty を利用するオプションだそうです。--rm はコンテナ終了時にコンテナ自動的に削除します。
> docker run -it --rm xxxxx/cheers2019イメージを共有できるようにする (docker push)
Docker Hub registry にpush(shipする?)し、共有できるようです。
> docker login; docker push xxxxx/cheers2019サンプルには他にsummer2019, halloween2019, birthday2019があり、全て同じような内容なようでした。。。
- CUI の使い方はここにドキュメントがありました。
- 振り返ってみるとCUIではログインや認証に関する操作をしませんでした。多分、Docker Desktop for Windows が全て良きにはかってくれたのだと思います。
Google Cloud Platform で動かしてみるのが、次のステップなのだが。
参考にさせていただきました。ありがとうございます。
- 投稿日:2019-12-01T15:35:48+09:00
Docker で Oracle Database 12c を動かす
なぜ Docker で動かしたのか
Oracle Database 12c の勉強をしようと思って macOS で動かすにはどうしたらいいのか探していたら。。。
macOS に対応したイメージがない!そして macOS で動かしている方がいらっしゃる!
ということで、検索して出てきたブログを参考にさせていただき、Dockerで動かそうと思い立ちました。(リンクしていいのかわからないので Oracle Database Docker などで検索してください。。)
Docker もよく聞くけど仕事で使ってないし触っておくか!と思ったのでちょうどよかったです。
これやったの去年の10月なので結構前ですね。。記事にするの遅すぎました。。
備忘録として残しておきます。環境
当時の実行環境はこちらでした。
macOS High Sierra 10.13.6
メモリ 8GBそしてかかった時間は120分以上。長かったです。
準備
私が実施した手順を実行するには、
Docker を動かす環境を作り、
- Oracle
- GitHub
上記のアカウントを作成しておくとスムーズです。
ダウンロードするもの
Oracle
Oracle Database ソフトウェア・ダウンロードから、バイナリファイルをダウンロードします。
今回は (12.1.0.2.0) - Standard Edition (SE2) の Linux x86-64 を選択します。File 1, File 2 の両方をダウンロードします。そして Oracle SQL Developerで動かすため、こちらもダウンロードしておきます。
GitHub
Oracle が Docker イメージを作成するスクリプト群を GitHub 上に公開しているので、oracle/docker-images より「Clone or download」 を実施します。私は git clone して持ってきました。
$ git clone https://github.com/oracle/docker-images.git手順
参考ページを見ながら動かしてみました!
参考ページは Enterprise Edition でしたが、私は Standard Edition 2 なのでそこだけ注意します。ディレクトリの作成
GitHub から Clone してくるだけだと、どうやらディレクトリが足りない・・・?
と思ったらドキュメントが古かった。。
GitHub が更新されてディレクトリ構造が変わってました。(去年なのでもう直ってるかも)/docker-images/OracleDatabase/SingleInstance/dockerfiles/12.1.0.2/ここに Oracle からダウンロードした zip ファイルを配置します。
コマンドの実行
zip ファイルを配置したディレクトリから一つ上の階層に移動してコマンドを実行します。
Standard Edition なのでオプションに-s
を使用します。$ ./buildDockerImage.sh -v 12.1.0.2 -sこのコマンドを実行すると諸々ダウンロードが始まります。24ステップくらいあって長かった記憶。
ダウンロード完了後は以下のコマンドを実行します。
$ docker run --name orcl -p 1521:1521 -p 5500:5500 -v /Users/UchidaKento/develop/docker/oracle-database/12c/oradata:/opt/oracle/oradata \ > -e ORACLE_SID=orcl -e ORACLE_PDB=pdb1 oracle/database:12.1.0.2-se2このコマンドで失敗した場合は、
$ docker container ls -a上記のコマンドを実行して NAME が
orcl
のコンテナがあることを確認し、$ docker rm orclさらに上記コマンドでコンテナを消してから再実行してください。
成功すると以下のようにログが出力されます。
一行目の最後にパスワードが出力されているので忘れないよう注意!
また、Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))上記に SQL Developer で設定するホストとポートが出力されているのでこちらも忘れないよう注意してください。
ORACLE PASSWORD FOR SYS, SYSTEM AND PDBADMIN: oy6AobM8plM=1 LSNRCTL for Linux: Version 12.1.0.2.0 - Production on 07-OCT-2018 10:45:00 Copyright (c) 1991, 2014, Oracle. All rights reserved. Starting /opt/oracle/product/12.1.0.2/dbhome_1/bin/tnslsnr: please wait... TNSLSNR for Linux: Version 12.1.0.2.0 - Production System parameter file is /opt/oracle/product/12.1.0.2/dbhome_1/network/admin/listener.ora Log messages written to /opt/oracle/diag/tnslsnr/5b1f3208ff47/listener/alert/log.xml Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1))) Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521))) Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1))) STATUS of the LISTENER ------------------------ Alias LISTENER Version TNSLSNR for Linux: Version 12.1.0.2.0 - Production Start Date 07-OCT-2018 10:45:00 Uptime 0 days 0 hr. 0 min. 0 sec Trace Level off Security ON: Local OS Authentication SNMP OFF Listener Parameter File /opt/oracle/product/12.1.0.2/dbhome_1/network/admin/listener.ora Listener Log File /opt/oracle/diag/tnslsnr/5b1f3208ff47/listener/alert/log.xml Listening Endpoints Summary... (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1))) (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521))) The listener supports no services The command completed successfully Copying database files 1% complete 2% complete 27% complete Creating and starting Oracle instance 29% complete 32% complete 33% complete 34% complete 38% complete 42% complete 43% complete 45% complete Completing Database Creation 48% complete 51% complete 53% complete 62% complete 64% complete 72% complete Creating Pluggable Databases 78% complete 100% complete Look at the log file "/opt/oracle/cfgtoollogs/dbca/ORCL/ORCL.log" for further details. SQL*Plus: Release 12.1.0.2.0 Production on Sun Oct 7 11:11:12 2018 Copyright (c) 1982, 2014, Oracle. All rights reserved. Connected to: Oracle Database 12c Standard Edition Release 12.1.0.2.0 - 64bit Production SQL> System altered. SQL> Pluggable database altered. SQL> Disconnected from Oracle Database 12c Standard Edition Release 12.1.0.2.0 - 64bit Production The Oracle base remains unchanged with value /opt/oracle ######################### DATABASE IS READY TO USE! ######################### The following output is now a tail of the alert.log: Sun Oct 07 11:10:57 2018 XDB initialized. Sun Oct 07 11:11:09 2018 Thread 1 advanced to log sequence 12 (LGWR switch) Current log# 3 seq# 12 mem# 0: /opt/oracle/oradata/ORCL/redo03.log Sun Oct 07 11:11:12 2018 ALTER SYSTEM SET control_files='/opt/oracle/oradata/ORCL/control01.ctl' SCOPE=SPFILE; ALTER PLUGGABLE DATABASE PDB1 SAVE STATE Completed: ALTER PLUGGABLE DATABASE PDB1 SAVE STATE Sun Oct 07 11:19:27 2018 Warning: VKTM detected a time drift. Time drifts can result in an unexpected behavior such as time-outs. Please check trace file for more details.これで Docker にイメージが作成され、接続準備が完了しました。
止めるときは以下のコマンドを実行します。
$ docker stop orcl再度動かしたいときは以下のコマンドを実行します。
$ docker start orclSQL Developer の設定
Docker で動かしている状態で SQL Developer に設定してあげると接続できます。
最後に
去年やったことの備忘録なので、少し変わっている箇所はあるかもしれません。
その場合は適宜読み替えていただければと思います。もし間違っている箇所などございましたらご指摘ください。
- 投稿日:2019-12-01T15:10:20+09:00
Automatically Docker Daemon Boot on Windows Subsystem Linux(WSLにおけるdockerデーモンの自動起動)
動機
windows10 homeにwsl2でdockerを導入して、ついでにdocker-composeも積むことで最高の開発環境を作ろうとしたのだが、一度電源を落とすとログオンの度に手動で
daemon
くんを起動し直さなければならないことに気づいた。docker-compose.yml
でrestart:always
している関係上、できればWin10が再起動してしまってもログオンすればすぐにdaemon
くんには起きていてほしい……!TL; DR
cf. Docker Running Seamlessly in Windows Subsystem Linux
1.
sudo vi /usr/local/sbin/start_docker.sh
/usr/local/sbin/start_docker.sh#!/usr/bin/env bash # The first command will setup cgroups mounts on the subsystem # (this only needs to be done once per reboot), and the second # will bring up the docker service using systemd. sudo cgroupfs-mount sudo service docker start2. 実行権限を付与する
$ sudo chmod +x /usr/local/sbin/start_docker.sh # Lock down edit privileges $ sudo chmod 755 /usr/local/sbin/start_docker.sh3.
sudo vi /etc/sudoers
- 最下部に以下の項目を追記
/etc/sudoers# Enable docker services to start without sudo yourUserName ALL=(ALL:ALL) NOPASSWD: /bin/sh /usr/local/sbin/start_docker.sh4. タスクスケジューラでログオン時にwsl上のdockerを起動
- 全般
- 「最上位の特権で実行する」にチェック
- トリガー
- ログイン時 かつ 少し時間差を持って起動する
- 同時にやると意図せず事故るかもしれないので
- 操作
- プログラム:
C:\Windows\System32\bash.exe
- 引数の追加:
-c "sudo /bin/sh /usr/local/sbin/start_docker.sh"
- 条件
- 「AC電源に~」のチェックを外す
- 設定
- お好みで
5. 再起動してログオンし直したあと、
sudo service docker status
で動作を確認$ sudo service docker status * Docker is running私的解釈(自己中心的な解説)
1.
sudo vi /usr/local/sbin/start_docker.sh
start_docker.sh
というシェルスクリプトを/usr/local/sbin
というディレクトリに置いている。書き込みにはroot権限が必要なことに注意したい。vi で開くと読み込み限定になっているため、:w !sudo tee %
すればよさそう?(エディタ初心者並感)2.実行権限を付与する
chmod
コマンドを使用して、/usr/local/sbin/start_docker.sh
の権限を変更している。オプションに+x
を用いているので、"eXecution" を追加したことになる。これをただ単に付与するだけじゃなくて、対象ごとに数字で指定するやり方がchmod OOO
ということになる。
この操作により、/usr/local/sbin
に置かれているスクリプトをシステム側から実行できるようになる。3.
sudo vi /etc/sudoers
/etc/sudoers
にはsudo
周りのあれこれが設定されている(実行可能ユーザとかコマンドとか)。このファイルへの変更は即座に反映されるため、:w !sudo tee %
する前に誤字脱字等がないか念入りに確認すること(二敗)。もしミスすると、sudo
が使えません → 設定ファイルにエラーがあります!となって詰む。
もしそうなってしまったら、パスワードを再設定し直すときと同様に、powershell
かcmd.exe
からwsl -u root
してrootログインする解決法がある(sudo無しで/etc/sudoers
を変更できるユーザであるrootくんに頼んで修正する)4.タスクスケジューラでログオン時にwsl上のdockerを起動
おまけ
実は
/usr/local/sbin/start_docker.sh
の内容はdocker起動コマンドに限らずどんなものであれ実行できる(たとえばservice
に登録してあるものなど、常にsudo
が必要なものすべて)。インタラクティブ実行にならないように注意しつつ、ssh
やcron
などをここに追記しておくことで、ほとんど普通のサーバーと変わりない振る舞いをさせることができる。
上記の工程それぞれでファイル名を/usr/local/sbin/WSL_autostart.sh
などと変更して、そのファイルに適宜必要なコマンドを追記していくといいだろう。参照:
- 投稿日:2019-12-01T14:59:37+09:00
【Mac】Docker を使って最速で Python 3.x 環境を構築する
Mac は標準で Python 2.7 がインストールされていますので、Python 3.x の環境が必要な場合は、Pipenv や pyenv を使って環境構築することが多いと思います。
しかし、インストールに失敗したり、設定に手間取ったりすることが多かったので、Docker を使った Python 3.x 環境の構築方法をまとめておきます。
動作環境
- Mac OS X 10.14.6
Docker を使って Python 3.x 環境を構築
以下の URL から「Docker Desktop for Mac」をダウンロードし、インストールします。
https://hub.docker.com/editions/community/docker-ce-desktop-macDocker のインストールが完了したら、「docker version」コマンドを実行し、正しくインストールされているか確認してみましょう。
$ docker version Client: Docker Engine - Community Version: 19.03.5 API version: 1.40 Go version: go1.12.12 Git commit: 633a0ea Built: Wed Nov 13 07:22:34 2019 OS/Arch: darwin/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.5 API version: 1.40 (minimum version 1.12) Go version: go1.12.12 Git commit: 633a0ea Built: Wed Nov 13 07:29:19 2019 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.2.10 GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339 runc: Version: 1.0.0-rc8+dev GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657 docker-init: Version: 0.18.0 GitCommit: fec3683任意のフォルダを Python のプロジェクトフォルダとして作成し、そのフォルダ内に Python のソースファイルを配置します。
※この記事では、「/Users/username/work/python/helloworld」をプロジェクトフォルダとして使用します。$ cd /Users/username/work/python/helloworld $ echo 'print("Hello World!")' > helloworld.py「docker run」コマンドを実行し、Python の実行環境となるコンテナを起動します。
以下のオプションを指定します。
- -i (--interactive) : コンテナの標準入力にアタッチします。
- -t (--tty) : 疑似ターミナル (pseudo-TTY) を割り当てます。
- --rm : コンテナ終了時に、自動的にコンテナを削除します。
- -v (--volume) : ローカルのフォルダをコンテナ上にマウントします。(<ローカル上のフォルダ>:<コンテナ上のフォルダ>)
Docker イメージは、Docker Hub で公開されている「python:3.7-alpine」を使用します。
コマンド末尾の「/bin/sh」は、コンテナ起動時に実行されるコマンドです。
$ docker run -it --rm -v /Users/username/work/python/helloworld:/helloworld python:3.7-alpine /bin/shコンテナが起動したら、以下のコマンドを実行して、正しく動作しているか確認してみましょう。
/ # ls bin etc home media opt root sbin sys usr dev helloworld lib mnt proc run srv tmp var / # python --version Python 3.7.5プロジェクトフォルダに移動し、Python ファイルを実行します。
/ # cd helloworld/ /helloworld # python helloworld.py Hello World!「exit」コマンドを実行すると、コンテナを終了します。
/helloworld # exitコンテナ起動時にパッケージをインストール
コンテナは起動時に初期化されるので、起動毎に必要なパッケージをインストールする必要があります。
それでは面倒なので、新しい Docker イメージを作成し、コンテナ起動時に必要なパッケージがインストールされるようにします。
プロジェクトフォルダ内に Dockerfile を作成します。
Dockerfile# ベースとなる Docker イメージを指定 FROM python:3.7.5-alpine # プロジェクトフォルダを指定 ARG project_dir=/helloworld/ # requirements.txt をコンテナにコピー ADD requirements.txt $project_dir # requirements.txt に書かれたパッケージをインストール WORKDIR $project_dir RUN pip install -r requirements.txt「docker build」コマンドを実行し、新しい Docker イメージ「helloworld」を作成します。
$ docker build -t helloworld .新しく作成した Docker イメージ「helloworld」を指定して「docker run」コマンドを実行すると、コンテナ起動時に requirements.txt に書かれたパッケージがインストールされます。
$ docker run -it --rm -v /Users/username/work/python/helloworld:/helloworld helloworld /bin/sh
- 投稿日:2019-12-01T14:29:34+09:00
Docker/Rails/ReactをつかってHelloWorld!
初めまして。
プログラミングを始めてからあと四ヶ月で一年が経とうとしている。
本当に時間が立つのは早い...
今回は、RailsとReactを使って、HelloWorldをしてみる。
Railsを主にバックエンド、Reactをフロント、データベースはPostgresSQLを使用する。
1.Dockerで環境構築
2.RailsとReactの導入
- RailsTutorialを完走し、簡易的なアプリ開発経験があるレベル。
- ReactTutorial
- Dockerインストール
追記(注意事項)
記事を書き終わった後に、RailsへのReact導入の方法がこれがベストではない感じがしてきました。
https://qiita.com/ry_2718/items/9b824a3f9ca750ce403e
rails new . --skip-coffee --skip-turbolinks --skip-sprockets --webpack=vue
rails 5.1からはこれでAssetpiplineの代わりにwebpackを導入することができるみたい。
情報収拾の仕方を改めて考えさせられました。最近になってからは公式リファレンスや、検索機能に1ヶ月以内などを指定して、英語の記事でもGoogle翻訳を駆使しながら頑張って読んでいる...。Dockerで環境構築をする
Dockerとは?なぜDockerか。 (読まなくていい)(間違ってたらすいません)
そもそもOSとは
http://www.toha-search.com/it/os.htm
OSとはOperation System(オペレーティング・システム)の略で、アプリやデバイスを動作させるための基本となるソフトウェアのことです。 具体的には、キーボードやマウス・タッチパッドなどのデバイスから入力した情報をアプリケーションに伝え、またソフトウェアとハードウェアの連携を司る中枢的な役割を果たします。
つまり、OSはハードウェアや入力デバイス出力デバイス、アプリケーションなどを容易に操作するためのもの。
それで、このOSの上でどんな感じで仮想環境を作るかで違いがでる。
https://udemy.benesse.co.jp/development/web/docker.html
ハードウェアを仮想化し、複数のサーバを構築できる仕組みは変わりません。ただ、コンテナは1つのOSを共有して利用しているのに対し、仮想マシンはサーバごとにOSをインストールし動かしていきます。
つまり、
仮想マシンはホストOSの上でもう一つのOS(ゲストOS)を起動すること。(VirtualBoxとか)
virtual boxとかを使ったことがある人はわかると思うが、仮想化させたいOSイメージを指定した後、設定で仮想化したOSが使用するハードディスクやメモリの分割を行う。<-結果的にゲストOSとホストOSが同時にメモリを占有するので処理が重たいコンテナは仮想化をホストOSの上で行う(Dockerとか)
コンテナでは、ホストOSの上で直接仮想化する(ゲストOSを建てない)ので非常に動作が軽い。Docker上であれば基本的に環境の差異による影響を受けない
また、DockerにはDockerHubというのがあり、そこからすでに環境が構築されたテンプレートや、MySQLやRubyなどのツールや言語をDocker上にイメージとしてインストールしてくれる。Dockerの基本コマンド
とりあえず目を通して、どんな動作を行うコマンドがあるかみてください。
初心者用Docker基本コマンド一覧(新旧スタイル対応)
DockerComposeの基本Dockefileとdocker-compose.ymlの設定
まずはDockerで環境構築
$ mkdir myblog $ cd myblog $ touch {Dockerfile,docker-compose.yml}Dockerfileはこの記事が非常にわかりやすいです。
Docker初心者がRails + PostgreSQL or MySQLで仮想環境構築した手順を丁寧にまとめる
Dockerfile 解説 FROM dockerhubからイメージをダウンロード WORKDIR 作業ディレクトリの指定 RUN コマンドの実行 COPY 引数1を引数2にコピー yarnインストール参考docker for macでrails × yarn × webpackerのfront環境を整える
myblog/DockerfileFROM ruby:2.5.5 RUN apt-get update && apt-get install -y build-essential nodejs libpq-dev #yarnインストール webpackで必要になります。 RUN curl apt-transport-https wget && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && apt-get install -y yarn RUN mkdir /rails WORKDIR /rails COPY Gemfile /rails/Gemfile COPY Gemfile.lock /rails/Gemfile.lock RUN bundle install COPY . /railsdocker-composeはこの記事が非常にわかりやすいです
docker-compose.ymlの書き方について解説してみた
docker-compose 解説 version docker-composeの文法はバージョンごとにことなるので指定が必要 servise 動かすアプリケーションの指定。ここでは、webとdb。 他 Service設定する際の項目について docker-compose.ymlversion: '3' services: web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - .:/rails ports: - "3000:3000" #ポート3000番を開けてコンテナの3000番に転送 depends_on: - db db: image: postgres volumes: - datavol:/var/lib/postgresql/data volumes: datavol:Railsアプリを作る。
以下のコマンドを入力
$ touch {Gemfile,Gemfile.lock} $ echo "source 'https://rubygems.org' gem 'rails','5.1.4' gem 'pg', '~> 0.20.0'" > Gemfile $ docker-compose run web bundle exec rails new . --force --database=postgresql $ docker-compose buildここまででRailsサーバーを立ち上げる準備が整っているはずなので立ち上げてみる。
$ docker-compose up -d //サーバー起動 $ docker-compose run web rake db:create //db作成ここにアクセス
みなさんは成功したでしょうか??....Reactを導入
とりあえずRailsの初期画面から変更を行う。
コントローラーを作ろう
$ rails g controller StaticPages home about contactルートの設定
routes.rbRails.application.routes.draw do root 'static_pages#home' get '/about', to: 'static_pages#about' get '/contact', to: 'static_pages#contact' endこれでReactでviewに変更を加える準備ができました。
gem追加
$ echo "gem 'webpacker' gem 'react-rails'">>Gemfile $ docker-compose run web bundle updatewebpack設定
$ docker-compose run web rails webpacker:install $ docker-compose run web rails webpacker:install:reactここまでくると、app/assets/javascriptというファイルが作成される。
この中のファイルがreactファイルになっている。試しにrailsのviewに呼び出したいころではあるが、railsサーバーを再起動しないと反映されないのでrailsコンテナを再起動。
$ docker ps //稼働中のコンテナの表示 0739cbd77243 170064292a20 "bundle exec rails s…" 12 hours ago Up 12 hours 0.0.0.0:3000->3000/tcp myblog_web_1 0d302bae2084 postgres "docker-entrypoint.s…" 13 hours ago Up 13 hours 5432/tcp myblog_db_1上の場合だと
0739cbd77243
これがrailsコンテナのIDになるので、このIDを指定してコンテナの再起動をする$ docker restart 0739cbd77243 //コンテナ起動参考
Rails で postgresql を使う(インストールからマイグレーションまで)
Docker初心者がRails + PostgreSQL or MySQLで仮想環境構築した手順を丁寧にまとめる
既存のRailsアプリにReactを導入する方法
- 投稿日:2019-12-01T14:21:19+09:00
VPN ServerにはPritunlが便利
Free Wi-Fiなどを利用する際は、VPNに接続すると安全です。仕組みは、通信が暗号化されるトンネルのようなものを作り、そこにトラフィックを通すことで通信内容の傍受などを阻害する効果があります。つまり、Free Wi-Fiを利用して何らかのサービスにログインする際にidやpassを読み取られる危険などがあるわけですが、それを回避できます。
また、VPNを使うとVPN Serverを経由するため、IP AddressがそのServerのものに変わります。(ただし、使用するツールや環境変数に依存する場合あり)。
しかし、VPNはなかなか面倒で一番良いのは、サービスにインストールして使えるようにすることですが、費用がかかります。
今回は、Web UIから設定が行えるpritunlを使ってLocal NetworkにVPN Serverを立ててみようと思います。
https://github.com/Fridus/docker-pritunl
$ mkdir mongo $ sudo docker-compose up -ddocker-compose.ymlnetwork: image: busybox ports: - "9700:443" - "1194:1194/udp" restart: always tty: true mongo: image: mongo volumes: - ./mongo:/data/db restart: always net: container:network pritunl: image: fridus/pritunl privileged: true environment: - MONGO_URI=mongodb://127.0.0.1:27017/pritunl restart: always net: container:networkもしくはjippi/pritunlを使います。
#!/bin/bash datadir="$(dirname $(readlink -f "$0"))/data" echo "datadir=$datadir" mkdir -p $datadir/{mongodb,pritunl} touch $datadir/pritunl.conf sudo docker run \ --name=pritunl \ --detach \ --cap-add NET_ADMIN \ --network=bridge \ --restart=always \ -v $datadir/mongodb:/var/lib/mongodb \ -v $datadir/pritunl:/var/lib/pritunl \ -v $datadir/pritunl.conf:/etc/pritunl.conf \ -p 1194:1194/udp \ -p xxxxxx:xxxxx/tcp \ jippi/pritunl次に、web UIから設定を行います。
$ ifconfig 192.168.1.4 $ chromium https://192.168.1.4:9700 $ chromium https://localhost:9700 user,password:pritunl # IP : 192.168.1.4 # User -> Add Organization, Add User # Server -> Add Server(Port 1194/udp), Attach Organization, Start Server # User -> download profileあとは、VPN Clientをインストールして、DLしたprofileをインポートするだけです。clientは、Tunnelblickでもpritunlでもどちらでもいいですが、osによっていろいろなものがあります。
WANからアクセスする際は、ルーターにてポートフォワーディングなどをします。例えば、ルーターのGlobal IPが1.1.1.1だったとしましょう。そこで、1.1.1.1への特定のポートのアクセスを、ローカルネットワークの特定のポートに転送する設定です。(なお、現実では1.1.1.1はcloudflareのdnsです)
# global ipを調べる $ curl -sL ipinfo.ioただ、downloadしたprofile(xxx.ovpn)は、Local IPを指定していますので、設定ファイルを書き直さなければなりません。
$ aunpack default.tar $ vim vpn_default.ovpn - remote 192.168.1.4 1194 udp + remote 1.1.1.1 xxxxxx udpxxxxxxのところは、特定されにくそうな番号を指定すると良いです。それをdockerで指定しているポート、ここでは1194ですが、そこに転送する設定を保存します。これは、ルーターのポート転送(ポートフォワーディング)などの項目になります。つまり、WAN側からの特定のポートへのアクセスに対して、LAN側の特定ポートに転送する処理です。
1.1.1.1:xxxxx/udp -> 192.168.1.4:1194/udp
このようにすることで、例えば、iOSの
OpenVPN
というアプリでvpn_default.ovpn
を開き、キャリア回線(WAN)からVPN Serverに接続できるようになります。なお、ルータのポートを開放するため、比較的危険な設定になりますので注意してください。ただし、Global IPからLocal Networkにアクセスするにはこの方法が最も安全だと思います。通常、WAN側からLocal NetworkにSSHするような場合も多くの人はこういう方法を使ってるはず。もし接続がうまくいかない場合は、pritunlの設定もルーターのGlobal IPを指定して、Restart Serverします。そうしないと、Virtual Networkが起動せず、Local IPで接続しているうちはVirtual Networkが立ち上がっているので、Globalからもアクセスできますが、それが切断されるとGlobalからの接続もできなくなってしまいます。
Local NetworkにVPN Serverを立ち上げるメリット
先程、WANからSSHする場合、通常はルータのポート転送(ポートフォワーディング)を利用すると言いました。
しかし、Local NetworkにVPN Serverを立てている場合は別です。
WANから自前のVPN Serverを通すと、自宅ルータのGlobal IPのみならずLocal IPも取得することになります。これを利用して、Local Networkにある各Serverにもいつもどおりアクセスできることになります。つまり、以下のようなSSHが通ります。
~/.ssh/configHost usb HostName 192.168.1.33 Port 22 IdentityFile ~/.ssh/usb User syui通常、WAN側からSSHするには、以下のような内容になります。わざわざ自宅のルータIP(Global IP)をHostNameに変更して、ポート転送の設定までしなければなりません。
~/.ssh/configHost usb HostName 1.1.1.1 # Global IP Port 22222 # ポート転送のポート番号(22222 -> 192.168.1.33:22) IdentityFile ~/.ssh/usb User syuiなお、DDNSを利用している場合は別です。DDNSは、例えばルータ(自宅)のGlobal IP(変動する数字)を特定のドメイン名(固定の文字列)に変換します。よって、HostNameにはDDNSを書けばいいだけになります。VPNの設定ファイルでも同じ。
~/.ssh/configHost usb HostName github.com.ddns.syui # DDNS Port 22222 # ポート転送のポート番号(22222 -> 192.168.1.33:22) IdentityFile ~/.ssh/usb User syuixxx.opvn- remote 1.1.1.1 1194 udp + remote github.com.ddns.syui 22222 udpしかし、DDNSサービスは有料であることも多いので、私はGlobal IPを使うことが多いです。Global IPの変動は、privateのチャンネルなどを用意し、IPの変動があれば教えるようなcronを実行しておけばいいでしょう。
DDNS
DDNSには例えば以下のようなものがあります。ただ、安全性などは調査していません。
ddns.pboehm.de
ではnameは10日間更新がないと自動削除されます。https://github.com/pboehm/ddns
# example myowntest.d.pboehm.deddns is built around a small webservice, so that you can update your IP address simply by calling an URL periodically through curl. Hosts that haven't been updated for 10 days will be automatically removed. This can be configured in your own instance.
- 投稿日:2019-12-01T12:31:22+09:00
FILEベースCMS GRAVのインストール(Docker)
この記事の目的
FILEベースCMS GRAVのインストール方法を記載しています。
今回は CentOS7 上の Docker 環境下に GRAV を入れて立ち上げてみます。
手順としてコンテナをビルドするところから実施する手順としました。理由は後述。
前提事項
以下の環境で実施しました。
ホストOS: CentOS7 7.7.1908 (Core)
Docker: 1.13.1セットアップ
準備
Dockerfile 他のファイルを置くディレクトリを作成しておきます。
mkdir -p /home/vm/docker-gravgit clone
git clone
コマンドで関連するファイルをダウンロード今回は admin 画面も利用するので、
Dockerfile.gravcoreadmin
ファイルを利用します。cd /home/vm/docker-grav git clone https://github.com/dsavell/docker-grav.git . cp -p Dockerfile.gravcoreadmin Dockerfileコンテナのビルド
Docker コマンドでビルドを実施します。
docker build -t local/docker-grav:1.0 .できたらイメージを確認します。
docker images保存ディレクトリの作成
コンテンツを保存するフォルダやキャッシュ関連のフォルダを作成しておきます。
mkdir -p /home/vm/docker-grav/user mkdir -p /home/vm/docker-grav/backup mkdir -p /home/vm/docker-grav/cacheコンテナ実行
引数を渡してコンテナを実行します。
今回はローカルポート 9080 にバインドして起動しました。docker run -d -p 9080:80 -v /home/vm/docker-grav/cache:/var/www/grav/cache -v /home/vm/docker-grav/backup:/var/www/grav/backup -v /home/vm/docker-grav/user:/var/www/grav/user local/docker-grav:1.0確認
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9efae32cddc5 local/docker-grav:1.0 "/init-admin" About a minute ago Up About a minute 443/tcp, 0.0.0.0:9080->80/tcp trusting_ritchie使い方
ブラウザを起動してポート9080 でアクセスします。
終わりに
設定で各種プラグインやテーマを選択していくと、いくつかのPHPモジュールが必要となることがあります。今回も mbstring が足りず起動できなくなりました。その際には Dockerfile に php-mbstring を追加してビルドからやり直す必要があります。
GRAVはまだ活発に更新されているので、ちょくちょくと修正が入ります。
dsavell
さんのDocker Hub
も登録されているのですが、GRAVを更新すると動かなくなったりします。現にこの記事を作成するにあたって、ほかの方の記事も参考にしたのですが、変更がありそのままでは動かなかったりするため、自分で Dockerfile を修正してビルドする手順に落ち着きました。
参考記事
- 投稿日:2019-12-01T11:51:59+09:00
コンテナ型仮想化技術 Study07 / ストレージ
はじめに
お勉強のログです。Persistent Volume辺り。
関連記事
コンテナ型仮想化技術 Study01 / Docker基礎
コンテナ型仮想化技術 Study02 / Docker レジストリ
コンテナ型仮想化技術 Study03 / Docker Compose
コンテナ型仮想化技術 Study04 / Minikube & kubectl簡易操作
コンテナ型仮想化技術 Study05 / Pod操作
コンテナ型仮想化技術 Study06 / ReplicaSet, Deployment, Service
コンテナ型仮想化技術 Study06' / Kubernetesネットワーク問題判別
コンテナ型仮想化技術 Study07 / ストレージ
コンテナ型仮想化技術 Study08 / Statefulset, Ingress
コンテナ型仮想化技術 Study09 / Helm参考情報
Persistent Volumes
【図解】初心者にも分かる iSCSI の仕組み ~NAS(NFS)との違いやメリット,デメリット~
ウマいストレージの選び方。ストレージの種類の整理
基本、コンテナは独立した稼働環境で、ディスクのイメージもそれぞれ独立していますが、コンテナ間(Pod間)で共有したい情報もあります。その場合、各コンテナから共有できるディスクをアクセスする必要がありますが、共有のための具体的なストレージ実装を抽象化して柔軟に構成できる仕組みをKubernetesでは提供しており、永続ボリューム/Persistent Volumeなどと呼ばれているようです。
利用できるストレージの実装方式はいくつかあり、それぞれ特徴も異なります。例えば以下のようなものがあるようです。
- emptyDir: 同一Pod内のコンテナでノード上のディスクを共有する仕組み。Podをまたぐと共有できない。Pod終了時に削除される。一時的な利用で使われる?
- hostPath: 同一ノード内のコンテナでノード上のディスクを共有する仕組み。ノードのディスクを使うため、別のノードのPodとは共有できない。シングルノード前提でしか使えない。
- NFS: ネットワーク経由で複数ノードからディスクを共有する仕組み。ノードを跨って複数コンテナからディスク共有可能。同時に複数のコンテナからReadWriteモードでマウント可能。
- GlasterFS: OSSのスケーラブルな分散ファイルシステム。ノードを跨って複数コンテナからディスク共有可能。同時に複数のコンテナからReadWriteモードでマウント可能。
- iSCSI: SCSIプロトコルをTCP/IPネットワーク経由で使用するためのプロトコル。ReadWriteモードで接続できるノードは1時点で1つ。
Force write, 排他制御, パフォーマンスあたりが気になる所ですが...
関連リソースの整理
Podで共有するストレージの構成の仕方として、大きくStatic Provisioning / Dynamic Provisioning という2種類の方法があります。
参考: Persistent Volumesそれぞれで定義しなければいけないリソースが若干異なります。
Static Provisioning
- PersistentVolume(PV): 使用するストレージサービス(NFS,GlasterFSなど)に応じて、それらのサービスを利用するための情報を管理します。これによりストレージサービスの実装が隠蔽されます。
- PersistentVolumeClaim(PVC): 名前の通り、PersistentVolumeに対する"要求"を管理するものです。どのPVを利用して、どういうモード(Read/Write)でアクセスして、どのくらいのサイズを確保するか、といったことを定義します。
事前に、利用するストレージサービスの構成(NFSサーバーやGlusterFSのサーバー構成など)は行っておき、それに応じたPV, PVCをKubernetes Clusterリソースとして定義し、PodからはPVCを指定して共有ストレージを利用する、という流れになります。
Dynamic Provisioning
参考: ボリュームの動的プロビジョニング(Dynamic Volume Provisioning)
- StorageClass: PVを動的に作成するための情報を管理するリソース。使用するストレージサービスに応じて、PVを動的に作成(Provisioning)するためのProvisioner(pluginモジュール)などを指定することになります。
新たにStorageClassというリソースが関連します。GlusterFSなど動的にストレージを確保するストレージサービスと組み合わせることで、PVを静的に定義するのではなく、PVの定義含めてストレージを動的にProvisioningすることができます。
環境整備
仮想NFSサーバー
以下のVagrantファイルをそのまま使って、VirtualBox上にNFSサーバー用のゲストOSを立てます。
https://github.com/takara9/vagrant-nfs/
git clone
してvagrant up
c:\y\Vagrant>git clone https://github.com/takara9/vagrant-nfs Cloning into 'vagrant-nfs'... remote: Enumerating objects: 26, done. remote: Total 26 (delta 0), reused 0 (delta 0), pack-reused 26 Unpacking objects: 100% (26/26), done. c:\y\Vagrant>cd vagrant-nfs c:\y\Vagrant\vagrant-nfs>vagrant up Bringing machine 'nfsserver' up with 'virtualbox' provider... ==> nfsserver: Importing base box 'ubuntu/xenial64'... ==> nfsserver: Matching MAC address for NAT networking... ==> nfsserver: Checking if box 'ubuntu/xenial64' version '20190613.1.0' is up to date... ==> nfsserver: A newer version of the box 'ubuntu/xenial64' for provider 'virtualbox' is ==> nfsserver: available! You currently have version '20190613.1.0'. The latest is version ==> nfsserver: '20191126.1.0'. Run `vagrant box update` to update. ==> nfsserver: Setting the name of the VM: vagrant-nfs_nfsserver_1574923150593_32019 ==> nfsserver: Clearing any previously set network interfaces... ==> nfsserver: Preparing network interfaces based on configuration... nfsserver: Adapter 1: nat nfsserver: Adapter 2: hostonly ==> nfsserver: Forwarding ports... nfsserver: 22 (guest) => 2222 (host) (adapter 1) ==> nfsserver: Running 'pre-boot' VM customizations... ==> nfsserver: Booting VM... ==> nfsserver: Waiting for machine to boot. This may take a few minutes... nfsserver: SSH address: 127.0.0.1:2222 nfsserver: SSH username: vagrant nfsserver: SSH auth method: private key nfsserver: nfsserver: Vagrant insecure key detected. Vagrant will automatically replace nfsserver: this with a newly generated keypair for better security. nfsserver: nfsserver: Inserting generated public key within guest... nfsserver: Removing insecure key from the guest if it's present... nfsserver: Key inserted! Disconnecting and reconnecting using new SSH key... ==> nfsserver: Machine booted and ready! ==> nfsserver: Checking for guest additions in VM... nfsserver: The guest additions on this VM do not match the installed version of nfsserver: VirtualBox! In most cases this is fine, but in rare cases it can nfsserver: prevent things such as shared folders from working properly. If you see nfsserver: shared folder errors, please make sure the guest additions within the nfsserver: virtual machine match the version of VirtualBox you have installed on nfsserver: your host and reload your VM. nfsserver: nfsserver: Guest Additions Version: 5.1.38 nfsserver: VirtualBox Version: 6.0 ==> nfsserver: Setting hostname... ==> nfsserver: Configuring and enabling network interfaces... ==> nfsserver: Mounting shared folders... nfsserver: /vagrant => C:/y/Vagrant/vagrant-nfs ==> nfsserver: Running provisioner: ansible_local... nfsserver: Installing Ansible... Vagrant has automatically selected the compatibility mode '2.0' according to the Ansible version installed (2.9.1). Alternatively, the compatibility mode can be specified in your Vagrantfile: https://www.vagrantup.com/docs/provisioning/ansible_common.html#compatibility_mode nfsserver: Running ansible-playbook... PLAY [nfsserver] *************************************************************** TASK [Gathering Facts] ********************************************************* ok: [nfsserver] TASK [Create export dir] ******************************************************* changed: [nfsserver] TASK [Ensure NFS utilities are installed.] ************************************* [DEPRECATION WARNING]: Invoking "apt" only once while using a loop via squash_actions is deprecated. Instead of using a loop to supply multiple items and specifying `name: "{{ item }}"`, please use `name: ['nfs-common', 'nfs- kernel-server']` and remove the loop. This feature will be removed in version 2.11. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg. changed: [nfsserver] => (item=[u'nfs-common', u'nfs-kernel-server']) [WARNING]: Updating cache and auto-installing missing dependency: python-apt TASK [copy /etc/exports] ******************************************************* changed: [nfsserver] TASK [restart nfs server] ****************************************************** changed: [nfsserver] PLAY RECAP ********************************************************************* nfsserver : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0仮想GlusterFSクラスタ
以下のVagrantファイルをそのまま使って、VirtualBox上にGlusterFSのクラスタを構成します(heteki+Glusterクラスタx3の合計4ノード)。
https://github.com/takara9/vagrant-glusterfsc:\y\Vagrant>git clone https://github.com/takara9/vagrant-glusterfs Cloning into 'vagrant-glusterfs'... remote: Enumerating objects: 50, done. remote: Counting objects: 100% (50/50), done. remote: Compressing objects: 100% (37/37), done. remote: Total 126 (delta 26), reused 30 (delta 12), pack-reused 76 eceiving objects: 70% (89/ Receiving objects: 100% (126/126), 29.01 KiB | 345.00 KiB/s, done. Resolving deltas: 100% (56/56), done. c:\y\Vagrant>cd vagrant-glusterfs c:\y\Vagrant\vagrant-glusterfs>vagrant up Bringing machine 'gluster1' up with 'virtualbox' provider... Bringing machine 'gluster2' up with 'virtualbox' provider... Bringing machine 'gluster3' up with 'virtualbox' provider... Bringing machine 'heketi' up with 'virtualbox' provider... ==> gluster1: Importing base box 'ubuntu/xenial64'... ==> gluster1: Matching MAC address for NAT networking... ==> gluster1: Checking if box 'ubuntu/xenial64' version '20190613.1.0' is up to date... ==> gluster1: A newer version of the box 'ubuntu/xenial64' for provider 'virtualbox' is ==> gluster1: available! You currently have version '20190613.1.0'. The latest is version ==> gluster1: '20191126.1.0'. Run `vagrant box update` to update. ==> gluster1: Setting the name of the VM: vagrant-glusterfs_gluster1_1574936789288_7817 ==> gluster1: Clearing any previously set network interfaces... ==> gluster1: Preparing network interfaces based on configuration... gluster1: Adapter 1: nat gluster1: Adapter 2: hostonly ==> gluster1: Forwarding ports... gluster1: 22 (guest) => 2222 (host) (adapter 1) ==> gluster1: Running 'pre-boot' VM customizations... ==> gluster1: Booting VM... ==> gluster1: Waiting for machine to boot. This may take a few minutes... gluster1: SSH address: 127.0.0.1:2222 gluster1: SSH username: vagrant gluster1: SSH auth method: private key gluster1: gluster1: Vagrant insecure key detected. Vagrant will automatically replace gluster1: this with a newly generated keypair for better security. gluster1: gluster1: Inserting generated public key within guest... gluster1: Removing insecure key from the guest if it's present... gluster1: Key inserted! Disconnecting and reconnecting using new SSH key... ==> gluster1: Machine booted and ready! ==> gluster1: Checking for guest additions in VM... gluster1: The guest additions on this VM do not match the installed version of gluster1: VirtualBox! In most cases this is fine, but in rare cases it can gluster1: prevent things such as shared folders from working properly. If you see gluster1: shared folder errors, please make sure the guest additions within the gluster1: virtual machine match the version of VirtualBox you have installed on gluster1: your host and reload your VM. gluster1: gluster1: Guest Additions Version: 5.1.38 gluster1: VirtualBox Version: 6.0 ==> gluster1: Setting hostname... ==> gluster1: Configuring and enabling network interfaces... ==> gluster1: Mounting shared folders... gluster1: /vagrant => C:/y/Vagrant/vagrant-glusterfs ==> gluster1: Running provisioner: shell... gluster1: Running: inline script ==> gluster1: Running provisioner: ansible_local... gluster1: Installing Ansible... Vagrant has automatically selected the compatibility mode '2.0' according to the Ansible version installed (2.9.1). Alternatively, the compatibility mode can be specified in your Vagrantfile: https://www.vagrantup.com/docs/provisioning/ansible_common.html#compatibility_mode gluster1: Running ansible-playbook... PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [gluster1] TASK [Add GlusterFS Repository] ************************************************ changed: [gluster1] TASK [Ensure PKG are installed.] *********************************************** changed: [gluster1] TASK [cp ssh-key] ************************************************************** changed: [gluster1] PLAY RECAP ********************************************************************* gluster1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ==> gluster2: Importing base box 'ubuntu/xenial64'... ==> gluster2: Matching MAC address for NAT networking... ==> gluster2: Checking if box 'ubuntu/xenial64' version '20190613.1.0' is up to date... ==> gluster2: Setting the name of the VM: vagrant-glusterfs_gluster2_1574936997945_17908 ==> gluster2: Fixed port collision for 22 => 2222. Now on port 2200. ==> gluster2: Clearing any previously set network interfaces... ==> gluster2: Preparing network interfaces based on configuration... gluster2: Adapter 1: nat gluster2: Adapter 2: hostonly ==> gluster2: Forwarding ports... gluster2: 22 (guest) => 2200 (host) (adapter 1) ==> gluster2: Running 'pre-boot' VM customizations... ==> gluster2: Booting VM... ==> gluster2: Waiting for machine to boot. This may take a few minutes... gluster2: SSH address: 127.0.0.1:2200 gluster2: SSH username: vagrant gluster2: SSH auth method: private key gluster2: gluster2: Vagrant insecure key detected. Vagrant will automatically replace gluster2: this with a newly generated keypair for better security. gluster2: gluster2: Inserting generated public key within guest... gluster2: Removing insecure key from the guest if it's present... gluster2: Key inserted! Disconnecting and reconnecting using new SSH key... ==> gluster2: Machine booted and ready! ==> gluster2: Checking for guest additions in VM... gluster2: The guest additions on this VM do not match the installed version of gluster2: VirtualBox! In most cases this is fine, but in rare cases it can gluster2: prevent things such as shared folders from working properly. If you see gluster2: shared folder errors, please make sure the guest additions within the gluster2: virtual machine match the version of VirtualBox you have installed on gluster2: your host and reload your VM. gluster2: gluster2: Guest Additions Version: 5.1.38 gluster2: VirtualBox Version: 6.0 ==> gluster2: Setting hostname... ==> gluster2: Configuring and enabling network interfaces... ==> gluster2: Mounting shared folders... gluster2: /vagrant => C:/y/Vagrant/vagrant-glusterfs ==> gluster2: Running provisioner: shell... gluster2: Running: inline script ==> gluster2: Running provisioner: ansible_local... gluster2: Installing Ansible... Vagrant has automatically selected the compatibility mode '2.0' according to the Ansible version installed (2.9.1). Alternatively, the compatibility mode can be specified in your Vagrantfile: https://www.vagrantup.com/docs/provisioning/ansible_common.html#compatibility_mode gluster2: Running ansible-playbook... PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [gluster2] TASK [Add GlusterFS Repository] ************************************************ changed: [gluster2] TASK [Ensure PKG are installed.] *********************************************** changed: [gluster2] TASK [cp ssh-key] ************************************************************** changed: [gluster2] PLAY RECAP ********************************************************************* gluster2 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ==> gluster3: Importing base box 'ubuntu/xenial64'... ==> gluster3: Matching MAC address for NAT networking... ==> gluster3: Checking if box 'ubuntu/xenial64' version '20190613.1.0' is up to date... ==> gluster3: Setting the name of the VM: vagrant-glusterfs_gluster3_1574937198478_31337 ==> gluster3: Fixed port collision for 22 => 2222. Now on port 2201. ==> gluster3: Clearing any previously set network interfaces... ==> gluster3: Preparing network interfaces based on configuration... gluster3: Adapter 1: nat gluster3: Adapter 2: hostonly ==> gluster3: Forwarding ports... gluster3: 22 (guest) => 2201 (host) (adapter 1) ==> gluster3: Running 'pre-boot' VM customizations... ==> gluster3: Booting VM... ==> gluster3: Waiting for machine to boot. This may take a few minutes... gluster3: SSH address: 127.0.0.1:2201 gluster3: SSH username: vagrant gluster3: SSH auth method: private key gluster3: gluster3: Vagrant insecure key detected. Vagrant will automatically replace gluster3: this with a newly generated keypair for better security. gluster3: gluster3: Inserting generated public key within guest... gluster3: Removing insecure key from the guest if it's present... gluster3: Key inserted! Disconnecting and reconnecting using new SSH key... ==> gluster3: Machine booted and ready! ==> gluster3: Checking for guest additions in VM... gluster3: The guest additions on this VM do not match the installed version of gluster3: VirtualBox! In most cases this is fine, but in rare cases it can gluster3: prevent things such as shared folders from working properly. If you see gluster3: shared folder errors, please make sure the guest additions within the gluster3: virtual machine match the version of VirtualBox you have installed on gluster3: your host and reload your VM. gluster3: gluster3: Guest Additions Version: 5.1.38 gluster3: VirtualBox Version: 6.0 ==> gluster3: Setting hostname... ==> gluster3: Configuring and enabling network interfaces... ==> gluster3: Mounting shared folders... gluster3: /vagrant => C:/y/Vagrant/vagrant-glusterfs ==> gluster3: Running provisioner: shell... gluster3: Running: inline script ==> gluster3: Running provisioner: ansible_local... gluster3: Installing Ansible... Vagrant has automatically selected the compatibility mode '2.0' according to the Ansible version installed (2.9.1). Alternatively, the compatibility mode can be specified in your Vagrantfile: https://www.vagrantup.com/docs/provisioning/ansible_common.html#compatibility_mode gluster3: Running ansible-playbook... PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [gluster3] TASK [Add GlusterFS Repository] ************************************************ changed: [gluster3] TASK [Ensure PKG are installed.] *********************************************** changed: [gluster3] TASK [cp ssh-key] ************************************************************** changed: [gluster3] PLAY RECAP ********************************************************************* gluster3 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ==> heketi: Importing base box 'ubuntu/xenial64'... ==> heketi: Matching MAC address for NAT networking... ==> heketi: Checking if box 'ubuntu/xenial64' version '20190613.1.0' is up to date... ==> heketi: Setting the name of the VM: vagrant-glusterfs_heketi_1574937397127_53647 ==> heketi: Fixed port collision for 22 => 2222. Now on port 2202. ==> heketi: Clearing any previously set network interfaces... ==> heketi: Preparing network interfaces based on configuration... heketi: Adapter 1: nat heketi: Adapter 2: hostonly ==> heketi: Forwarding ports... heketi: 22 (guest) => 2202 (host) (adapter 1) ==> heketi: Running 'pre-boot' VM customizations... ==> heketi: Booting VM... ==> heketi: Waiting for machine to boot. This may take a few minutes... heketi: SSH address: 127.0.0.1:2202 heketi: SSH username: vagrant heketi: SSH auth method: private key heketi: heketi: Vagrant insecure key detected. Vagrant will automatically replace heketi: this with a newly generated keypair for better security. heketi: heketi: Inserting generated public key within guest... heketi: Removing insecure key from the guest if it's present... heketi: Key inserted! Disconnecting and reconnecting using new SSH key... ==> heketi: Machine booted and ready! ==> heketi: Checking for guest additions in VM... heketi: The guest additions on this VM do not match the installed version of heketi: VirtualBox! In most cases this is fine, but in rare cases it can heketi: prevent things such as shared folders from working properly. If you see heketi: shared folder errors, please make sure the guest additions within the heketi: virtual machine match the version of VirtualBox you have installed on heketi: your host and reload your VM. heketi: heketi: Guest Additions Version: 5.1.38 heketi: VirtualBox Version: 6.0 ==> heketi: Setting hostname... ==> heketi: Configuring and enabling network interfaces... ==> heketi: Mounting shared folders... heketi: /vagrant => C:/y/Vagrant/vagrant-glusterfs ==> heketi: Running provisioner: shell... heketi: Running: inline script ==> heketi: Running provisioner: ansible_local... heketi: Installing Ansible... Vagrant has automatically selected the compatibility mode '2.0' according to the Ansible version installed (2.9.1). Alternatively, the compatibility mode can be specified in your Vagrantfile: https://www.vagrantup.com/docs/provisioning/ansible_common.html#compatibility_mode heketi: Running ansible-playbook... PLAY [heketi] ****************************************************************** TASK [Gathering Facts] ********************************************************* ok: [heketi] TASK [Add GlusterFS Repository] ************************************************ changed: [heketi] TASK [Ensure PKG are installed.] *********************************************** changed: [heketi] TASK [cp id_rsa root] ********************************************************** changed: [heketi] TASK [cp id_rsa vagrant] ******************************************************* changed: [heketi] TASK [download] **************************************************************** changed: [heketi] TASK [extract tar] ************************************************************* changed: [heketi] TASK [cp heketi.json] ********************************************************** changed: [heketi] TASK [cp heketi.service for systemd] ******************************************* changed: [heketi] TASK [reload systemd service] ************************************************** changed: [heketi] TASK [Make sure a service is running] ****************************************** changed: [heketi] PLAY RECAP ********************************************************************* heketi : ok=11 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ==> heketi: Running provisioner: ansible_local... Vagrant has automatically selected the compatibility mode '2.0' according to the Ansible version installed (2.9.1). Alternatively, the compatibility mode can be specified in your Vagrantfile: https://www.vagrantup.com/docs/provisioning/ansible_common.html#compatibility_mode heketi: Running ansible-playbook... PLAY [heketi] ****************************************************************** TASK [Gathering Facts] ********************************************************* ok: [heketi] TASK [create gluster cluster] ************************************************** changed: [heketi] TASK [add node] **************************************************************** changed: [heketi] => (item=172.20.1.21) changed: [heketi] => (item=172.20.1.22) changed: [heketi] => (item=172.20.1.23) TASK [add device 1] ************************************************************ changed: [heketi] TASK [add device 2] ************************************************************ changed: [heketi] TASK [add device 3] ************************************************************ changed: [heketi] PLAY RECAP ********************************************************************* heketi : ok=6 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0シングルノード構成での操作例 (minikube)
Static Provisioning
NFSを共有ストレージとして利用してみます。
minikubeから上で作成したNFSを使用する想定です。共有ストレージの準備
これは、上で作成したNFSをそのまま使います。
NFSサーバー(172.16.20.10)にsshで接続して、NFSとして公開しているファイルシステムの状況を確認してみます。
vagrant@nfsserver:~$ sudo exportfs -v /export 172.16.20.0/24(rw,async,wdelay,insecure,root_squash,no_subtree_check,fsid=0,sec=sys,rw,root_squash,no_all_squash)/exportというディレクトリが公開されてる状態です。
busyboxのコンテナを稼働させるPodから、NFSサーバーにpingが通ることを確認しておきます。
vagrant@minikube:~$ kubectl run -it busybox --restart=Never --rm --image=busybox sh If you don't see a command prompt, try pressing enter. / # ifconfig eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:07 inet addr:172.17.0.7 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:18 errors:0 dropped:0 overruns:0 frame:0 TX packets:10 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1516 (1.4 KiB) TX bytes:868 (868.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) / # ping -c 3 172.16.20.10 PING 172.16.20.10 (172.16.20.10): 56 data bytes 64 bytes from 172.16.20.10: seq=0 ttl=62 time=0.756 ms 64 bytes from 172.16.20.10: seq=1 ttl=62 time=1.010 ms 64 bytes from 172.16.20.10: seq=2 ttl=62 time=1.384 ms --- 172.16.20.10 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.756/1.050/1.384 msping通りましたが、あれ?PodにアサインされるIPアドレスって、クラスター内で閉じてるんじゃなかったっけ???外には出ていけるのか...
/ # ping -c 3 www.google.com PING www.google.com (172.217.31.132): 56 data bytes 64 bytes from 172.217.31.132: seq=0 ttl=44 time=20.332 ms 64 bytes from 172.217.31.132: seq=1 ttl=44 time=19.837 ms 64 bytes from 172.217.31.132: seq=2 ttl=44 time=19.817 ms --- www.google.com ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 19.817/19.995/20.332 ms名前解決もできてるな。
ちなみに、NFSサーバー側からこのPodのアドレス(172.17.0.7)にはPingは通らなかった。ま、それはそうだろうな。(でもPodが動いているノード上からはPing通った。)
うーん、ネットワークむつかしね。とりあえずbusyboxからNFSへのpingが通るので準備としてはOKっぽい。
PersistentVolume(PV)作成
以下のマニフェストをそのまま使います。
https://github.com/takara9/codes_for_lessons/blob/master/step11/nfs/nfs-pv.ymlvagrant@minikube:~/codes_for_lessons/step11/nfs$ kubectl apply -f nfs-pv.yml persistentvolume/nfs-1 created vagrant@minikube:~/codes_for_lessons/step11/nfs$ kubectl get pv -o wide NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE nfs-1 100Mi RWX Retain Available 27s FilesystemPersistentVolumeClaim(PVC)作成
以下のマニフェストをそのまま使います。
https://github.com/takara9/codes_for_lessons/blob/master/step11/nfs/nfs-pvc.ymlvagrant@minikube:~/codes_for_lessons/step11/nfs$ kubectl apply -f nfs-pvc.yml persistentvolumeclaim/nfs-1 created vagrant@minikube:~/codes_for_lessons/step11/nfs$ kubectl get pv,pvc -o wide NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE persistentvolume/nfs-1 100Mi RWX Retain Bound default/nfs-1 4m34s Filesystem NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE persistentvolumeclaim/nfs-1 Bound nfs-1 100Mi RWX 33s FilesystemPodの作成
以下のマニフェストをそのまま使います。
https://github.com/takara9/codes_for_lessons/blob/master/step11/nfs/nfs-client.ymlPod単体ではなくDeploymentの定義となってるので、Replicasetから複数Podが作成されることになります(replica数:2)。
vagrant@minikube:~/codes_for_lessons/step11/nfs$ kubectl get pv,pvc,pod -o wide NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE persistentvolume/nfs-1 100Mi RWX Retain Bound default/nfs-1 22m Filesystem NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE persistentvolumeclaim/nfs-1 Bound nfs-1 100Mi RWX 18m Filesystem NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/nfs-client-7c4b8fc57f-nnjzp 1/1 Running 0 27s 172.17.0.8 minikube <none> <none> pod/nfs-client-7c4b8fc57f-p4sn2 1/1 Running 0 27s 172.17.0.7 minikube <none> <none>確認
これで、2つのPodからストレージが共有されているはず。
NFSサーバー側のステータスを見てみると...
vagrant@nfsserver:~$ showmount -a All mount points on nfsserver: 172.16.20.1:/export172.16.20.1からマウントしているように見える。このIPアドレスは何者?マルチノード構成だったら、これが複数になる???
1つめのPodに入って、マウント状況確認し、マウントされているディレクトリに適当なファイル作ってみます。
Pod1vagrant@minikube:~$ kubectl exec -it nfs-client-7c4b8fc57f-nnjzp bash root@nfs-client-7c4b8fc57f-nnjzp:/# df -h Filesystem Size Used Avail Use% Mounted on overlay 9.7G 4.1G 5.6G 43% / tmpfs 64M 0 64M 0% /dev tmpfs 1000M 0 1000M 0% /sys/fs/cgroup 172.16.20.10:/export 9.7G 1.2G 8.5G 12% /mnt /dev/sda1 9.7G 4.1G 5.6G 43% /etc/hosts shm 64M 0 64M 0% /dev/shm tmpfs 1000M 12K 1000M 1% /run/secrets/kubernetes.io/serviceaccount tmpfs 1000M 0 1000M 0% /proc/acpi tmpfs 1000M 0 1000M 0% /proc/scsi tmpfs 1000M 0 1000M 0% /sys/firmware root@nfs-client-7c4b8fc57f-nnjzp:/# echo "aaaaa" > /mnt/test.txt root@nfs-client-7c4b8fc57f-nnjzp:/# ls /mnt/ test.txtもう1つのPodに入って、マウント状況確認し、マウントされているディレクトリのファイルを確認してみます。
Pod2vagrant@minikube:~$ kubectl exec -it nfs-client-7c4b8fc57f-p4sn2 bash root@nfs-client-7c4b8fc57f-p4sn2:/# df -h Filesystem Size Used Avail Use% Mounted on overlay 9.7G 4.1G 5.6G 43% / tmpfs 64M 0 64M 0% /dev tmpfs 1000M 0 1000M 0% /sys/fs/cgroup 172.16.20.10:/export 9.7G 1.2G 8.5G 12% /mnt /dev/sda1 9.7G 4.1G 5.6G 43% /etc/hosts shm 64M 0 64M 0% /dev/shm tmpfs 1000M 12K 1000M 1% /run/secrets/kubernetes.io/serviceaccount tmpfs 1000M 0 1000M 0% /proc/acpi tmpfs 1000M 0 1000M 0% /proc/scsi tmpfs 1000M 0 1000M 0% /sys/firmware root@nfs-client-7c4b8fc57f-p4sn2:/# ls /mnt test.txt root@nfs-client-7c4b8fc57f-p4sn2:/# cat /mnt/test.txt aaaaaNFSサーバー上でも、当然同じファイルが確認できます。
NFS_Servervagrant@nfsserver:~$ ls /export/ test.txt vagrant@nfsserver:~$ cat /export/test.txt aaaaa疑問
あれ?そういえば、PVCのマニフェストではstorageでサイズらしきものを設定しているのだが、NFSで公開されたものをマウントする場合、普通、クライアント側でサイズなんて意識しないよなぁ。Static Provisioningの場合はこのサイズは意味無いのかな?
nfs-pvc.yml抜粋.. resources: requests: storage: "100Mi" ...まとめ
※注意!
Static Provisioninの場合、PVCのstorageClassNameには必ず""(Null)を指定する必要があります。この項目を省略してしまうと、そのK8sクラスターのデフォルトのStorageClassを使用したDynamic Provisioningを行うものと認識されてしまいます。マルチノード構成での操作例
Dyanamic Provisioning
環境としては、マルチノード構成のK8sクラスターと、上で作成したGlusterFSを使用します。
構成イメージとしては以下の通り。(いずれもWindowsのVirtualBox上のゲストOSとして構成)
共有ストレージの準備
共有ストレージとして、上のGlusterFSを使用します。GlusterFSはheketi経由でコントロールする想定なので、masterノードからheketiにpingが通ることを確認しておきます。
vagrant@master:~$ ping -c 3 172.20.1.20 PING 172.20.1.20 (172.20.1.20) 56(84) bytes of data. 64 bytes from 172.20.1.20: icmp_seq=1 ttl=63 time=0.643 ms 64 bytes from 172.20.1.20: icmp_seq=2 ttl=63 time=0.765 ms 64 bytes from 172.20.1.20: icmp_seq=3 ttl=63 time=0.788 ms --- 172.20.1.20 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2006ms rtt min/avg/max/mdev = 0.643/0.732/0.788/0.063 msStorageClass作成
Dynamic Provisioningでは、PV(Persistent Volume)を静的に定義するのではなく、リクエストに応じて動的にプロビジョニングすることになります。その基になるStorage Classというリソースを事前に定義しておきます。
Storage Classを作成するために、以下のYamlをそのまま適用します。
https://github.com/takara9/codes_for_lessons/blob/master/step11/glusterfs/gfs-sc.ymlvagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl apply -f gfs-sc.yml storageclass.storage.k8s.io/gluster-heketi created確認
vagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl get sc NAME PROVISIONER AGE gluster-heketi kubernetes.io/glusterfs 26s vagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl describe sc gluster-heketi Name: gluster-heketi IsDefaultClass: No Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"gluster-heketi"},"parameters":{"resturl":"http://172.20.1.20:8080","restuser":"admin","restuserkey":"admin"},"provisioner":"kubernetes.io/glusterfs"} Provisioner: kubernetes.io/glusterfs Parameters: resturl=http://172.20.1.20:8080,restuser=admin,restuserkey=admin AllowVolumeExpansion: <unset> MountOptions: <none> ReclaimPolicy: Delete VolumeBindingMode: Immediate Events: <none>PersistentVolumeClaim(PVC)作成
上のStorageClassを使用してPVをリクエストするためのPVCを作成します。
以下のYamlをそのまま適用します。
https://github.com/takara9/codes_for_lessons/blob/master/step11/glusterfs/gfs-pvc.ymlvagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl apply -f gfs-pvc.yml persistentvolumeclaim/gvol-1 created確認
vagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE gvol-1 Bound pvc-152d576c-2ad9-11ea-8406-022ec1de99b7 10Gi RWX gluster-heketi 21s vagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl describe pvc gvol-1 Name: gvol-1 Namespace: default StorageClass: gluster-heketi Status: Bound Volume: pvc-152d576c-2ad9-11ea-8406-022ec1de99b7 Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"gvol-1","namespace":"default"},"spec":{"accessModes... pv.kubernetes.io/bind-completed: yes pv.kubernetes.io/bound-by-controller: yes volume.beta.kubernetes.io/storage-provisioner: kubernetes.io/glusterfs Finalizers: [kubernetes.io/pvc-protection] Capacity: 10Gi Access Modes: RWX VolumeMode: Filesystem Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ProvisioningSucceeded 43s persistentvolume-controller Successfully provisioned volume pvc-152d576c-2ad9-11ea-8406-022ec1de99b7 using kubernetes.io/glusterfs Mounted By: <none>vagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-152d576c-2ad9-11ea-8406-022ec1de99b7 10Gi RWX Delete Bound default/gvol-1 gluster-heketi 4m27s vagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl describe pv pvc-152d576c-2ad9-11ea-8406-022ec1de99b7 Name: pvc-152d576c-2ad9-11ea-8406-022ec1de99b7 Labels: <none> Annotations: Description: Gluster-Internal: Dynamically provisioned PV gluster.kubernetes.io/heketi-volume-id: dfcee042efd048237f65705e680064f6 gluster.org/type: file kubernetes.io/createdby: heketi-dynamic-provisioner pv.beta.kubernetes.io/gid: 2000 pv.kubernetes.io/bound-by-controller: yes pv.kubernetes.io/provisioned-by: kubernetes.io/glusterfs Finalizers: [kubernetes.io/pv-protection] StorageClass: gluster-heketi Status: Bound Claim: default/gvol-1 Reclaim Policy: Delete Access Modes: RWX VolumeMode: Filesystem Capacity: 10Gi Node Affinity: <none> Message: Source: Type: Glusterfs (a Glusterfs mount on the host that shares a pod's lifetime) EndpointsName: glusterfs-dynamic-152d576c-2ad9-11ea-8406-022ec1de99b7 EndpointsNamespace: 0xc0006c9190 Path: vol_dfcee042efd048237f65705e680064f6 ReadOnly: false Events: <none>Pod作成
上のPVCを利用するPodを作成します。以下のDeployment用のYamlを適用することで、同じファイルを共有するPodのレプリカを2つ作成します。
https://github.com/takara9/codes_for_lessons/blob/master/step11/glusterfs/gfs-client.ymlvagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl apply -f gfs-client.yml deployment.apps/gfs-client created確認
vagrant@master:~/codes_for_lessons/step11/glusterfs$ kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES gfs-client-6947c4c7fd-5d8fd 1/1 Running 0 27s 10.244.2.26 node2 <none> <none> gfs-client-6947c4c7fd-jfnn4 1/1 Running 0 27s 10.244.1.37 node1 <none> <none>1つ目のPodに接続して、マウント先にファイルを作成してみます。
vagrant@master:~$ kubectl exec -it gfs-client-6947c4c7fd-5d8fd sh # df -h Filesystem Size Used Avail Use% Mounted on overlay 9.7G 2.5G 7.3G 26% / tmpfs 64M 0 64M 0% /dev tmpfs 497M 0 497M 0% /sys/fs/cgroup 172.20.1.21:vol_dfcee042efd048237f65705e680064f6 10G 66M 10G 1% /mnt /dev/sda1 9.7G 2.5G 7.3G 26% /etc/hosts shm 64M 0 64M 0% /dev/shm tmpfs 497M 12K 497M 1% /run/secrets/kubernetes.io/serviceaccount tmpfs 497M 0 497M 0% /proc/acpi tmpfs 497M 0 497M 0% /proc/scsi tmpfs 497M 0 497M 0% /sys/firmware # date > /mnt/test.txt # cat /mnt/test.txt Mon Dec 30 08:04:38 UTC 2019もう一つのPodに接続して、マウント先ファイルを確認してみます。
vagrant@master:~$ kubectl exec -it gfs-client-6947c4c7fd-jfnn4 sh # cat /mnt/test.txt Mon Dec 30 08:04:38 UTC 2019同じ内容のファイルが確認できました。意図した通りにファイルが共有できています!
まとめ
- 投稿日:2019-12-01T10:27:11+09:00
docker windows10home でWEBアクセスできなくてハマった話
docker windows10home でWEBアクセスできなくてハマった話
ビルドは、とりあえずできた。
参考にしたサイト
Docker | docker build と Dockerfile でイメージをビルドする基本
Dockerfileがあるディレクトリに移動して、以下のコマンドでOKでした。
$ docker build ./ -t hello1201_2
はまりポイント
$ docker run --init -d -e PORT=81 -p 0.0.0.0:8081:81 hello1201_2
このコマンド後、ブラウザで、http://0.0.0.0:8081
だと、アクセスできませんでした。
いろいろ試したけど、ダメめでした。参考にしたのは、こちらのサイト
Docker入門日誌-その2- Webサーバ立ち上げ編
$ docker-machine ls
で出てくるURLを再確認します。
私の場合、
$ docker-machine ls
となっていたので、ブラウザで、http://192.168.99.100:8081
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default * virtualbox Running tcp://192.168.99.100:2376 v19.03.5
として、アクセスできました。解決できない気がしてたけど、Google先生! ありがとう!
Google検索は、以下の通りでした。
”docker ローカルPC WEBアクセスできない”
- 投稿日:2019-12-01T01:08:41+09:00
Tensorflow DockerでTensorBoardを使う
環境
Ubuntu 18.04
Docker 19.03手順
1. コンテナの起動。
$ docker run --runtime=nvidia -it -p [ホスト側のポート]:[コンテナ側のポート] tensorflow/tensorflow:latest-gpu-py3 bash-pオプションで
[ホスト側のポート]
にアクセスすると、[コンテナ側のポート]
にフォワードされるように起動する。
公開先のIPはデフォルトで0.0.0.0
が指定されている。($ docker ps
で確認できる。)【参考】
http://docs.docker.jp/engine/userguide/networking/default_network/binding.html
https://qiita.com/tifa2chan/items/a58e34019d4f10097a4d2. tensorboardの起動
# tensorboard --port [コンテナ側のポート] --logdir [logのディレクトリパス] --bind_all
--bind_all
もしくは--host=0.0.0.0
でIPを指定。【参考】
https://qrunch.net/@diatonic/entries/fPGdT6VC7FKEpCVm3. ブラウザで開く。
http://0.0.0.0:[ホスト側のポート]
をブラウザに入力する。
TensorBoard 2.0.0 http://0.0.0.0:[コンテナ側のポート]/
と表示されるが、ホストからは直接コンテナのポートにアクセスできないので、コンテナ起動時に指定した[ホスト側のポート]からアクセスする。