20190728のdockerに関する記事は16件です。

Julia+Jupyter Notebook環境をDockerで構築

概要

JuliaをJupyter Notebookで使える環境を手軽に再現できるようにするため、Dockerで環境構築していきます。
Jupyter公式のDocker imageをベースにして、データの永続化やパッケージの自動追加をできるようにします。

環境

  • OS: Ubuntu 18.04
  • Docker 18.09.8

手順

1. jupyter/datascience-notebookを取得

docker pull jupyter/datascience-notebook

2. コンテナを起動

docker run \
       -p 8888:8888 \
       --user root \
       --name mynotebook \
       jupyter/datascience-notebook

-pでポート番号、--userでユーザーの指定が必要です。コンテナ名の指定--nameは任意です。

3. Jupyter Notebookにアクセス

To access the notebook, open this file in a browser:
        file:///home/jovyan/.local/share/jupyter/runtime/nbserver-17-open.html
Or copy and paste one of these URLs:
        http://df19b359c643:8888/?token=xxxxx
     or http://127.0.0.1:8888/?token=xxxxx

表示されたURLをブラウザで開くとJupyter Notebookが使えます。
ちなみにJuliaだけでなくRとPythonも使用可能です。Jupyter公式のDocker imageについてはこのページが詳しいです。

データの永続化

このままではコンテナでの作業が保存されないので、ローカルのディレクトリをマウントします。

docker run -p 8888:8888 \
           -v ~/path/to/directory:/home/jovyan/work \
           --user root \
           --name mynotebook \
           jupyter/datascience-notebook

-vでマウントするディレクトリを指定します。ちなみにデフォルトユーザー名であるjovyanとはjupyterを使う人というような意味のようです

パッケージの追加を自動化

1. Dockerfileの作成

よく使うパッケージを自動で追加できるようにちょっとしたDockerfileを作成します。
例としてPlotsDifferentialEquationsを追加してみます。

Dockerfile
FROM jupyter/datascience-notebook
MAINTAINER yoshikiri

# Plotsを追加
RUN julia -e 'using Pkg; Pkg.add("Plots"); using Plots'

# DifferentialEquationsを追加
RUN julia -e 'using Pkg; Pkg.add("DifferentialEquations"); using DifferentialEquations'

REPLを起動せずコマンドでjulia文を実行するには-eオプションを使います。

julia -e 'println("hello, julia")'

2. DockerfileからDocker imageを作成

docker build -t notebook .

上記コマンド実行後、新たにDocker imageが作成されたことが確認できます。imageのバージョンを指定しないとlatestになります。

$ docker images
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
notebook                       latest              4233009a8db5        1 minutes ago      5.77GB

3. Docker imageからコンテナを起動

docker run -p 8888:8888 \
           -v ~/path/to/directory:/home/jovyan/work \
           --user root \
           --name mynotebook \
           notebook

最後のimage名を変更しただけです。

まとめ

  • jupyter/datascience-notebookでJulia (とR, Python) + Jupyter Notebook環境を構築
  • ボリュームをマウントしてデータを永続化
  • パッケージを自動で追加するDocker imageをDockerfileから作成
  • 作成したDockerfileをGitHubなどで共有すれば、どこでも同じ環境を構築可能

意見や間違いがあればコメントで教えていただけると大変ありがたいです。

参考文献

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

docker multistage buildとDockerHub

背景

Dockerのマルチステージビルド機能とDockerHubへのPushまでのメモ

用意するもの

※ Docker 17.05以上が必要です。

Dockerfile

マルチステージを用いるDockerfileと使わないDockerfileを用意します。
マルチステージビルドについては下記をご参照ください
Use multi-stage builds

ノーマル
FROM golang:1.12.7-alpine
LABEL multi_stage="no"
WORKDIR /app
RUN apk add --no-cache make && \
    rm -rf /var/cache/apk/* && \
    mkdir src
COPY ./src ./src
COPY ./Makefile .
RUN make
ENTRYPOINT ["./main"]
CMD [""]
マルチステージビルド
FROM golang:1.12.7-alpine AS builder
LABEL multi_stage="no"
WORKDIR /app
RUN apk add --no-cache make && \
    rm -rf /var/cache/apk/* && \
    mkdir src
COPY ./src ./src
COPY ./Makefile .
RUN make

FROM busybox
LABEL multi_stage="yes"
WORKDIR /app
COPY --from=builder /app/main .
# COPY --from=0でも前ステージを指定してることになるのでそちらでも可能
COPY ./test.ini .
ENTRYPOINT ["./main"]
CMD [""]

上記をそれぞれビルドします。できあがったイメージはこちらです。
タグはわかりやすいようにつけてます。
353MB => 3MBは優秀ですね。

$ docker image ls --filter 'label=multi_stage=no'
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
ryuichi1208/mumulti_stage_build   nomal               508808fe62ea        45 minutes ago      353MB

$ docker image ls --filter 'label=multi_stage=yes'
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
ryuichi1208/mumulti_stage_build   multi               b5c000ea4c0a        About an hour ago   3.25MB

DockerHubへPush

DockerHubへログインしてpushします。
詳細については下記をご参照ください。
Docker Hub Quickstart

Pushしたものはこちら。
それぞれマルチステージビルドを使ったものと使わなかったイメージです。

スクリーンショット 2019-07-28 21.44.19.png

他ホストからイメージしてRun

$ docker run ryuichi1208/multi_stage_build:multi

$ docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
ryuichi1208/multi_stage_build        multi               27cb320e59ac        2 hours ago         3.25MB
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ローカルで開発していたアプリをDocker化してみた(nginx+Flask+postgres)

はじめに

ローカルで作った簡易的なブログサービス(こちらの記事を参照)をDocker化してみました。正直この規模だと単一コンテナで十分だと思いますが、折角dockerをお勉強する機会なので、nginx(Webサーバ)gunicorn+flask(APサーバ)postgre(DBサーバ)でコンテナを分けて、docker-composeで全コンテナの統合管理をします。

docker構成

docker構成.jpeg

ディレクトリ構成

ローカルの任意の場所にこの構成で作ります。

TutorialBlog
 ├docker-compose.yml
 ├nignx/
 │ ├nginx.conf
 │ └Dockerfile
 ├app/
 │ ├templates/
 │ │ └(略)
 │ ├static/
 │ │ └(略)
 │ ├app.py
 │ ├models.py
 │ └Dockerfile
 ├postgres/
 │ ├initdb
 │ │ └createdb.sql
 │ └Dockerfile
 ├Pipfile
 ├Pipfile.lock
 └run.py

ブラウザ⇆localhost:80⇆nginx:80

ブラウザからのリクエストをlocalhostの80番ポートで受けてnginxコンテナ(nginx-server)の80番ポートに流す設定はdocker-compose.ymlに書きます。

docker-compose.yml
services:
  nginx-server:
    ports:
     - 80:80  #[localhost側のポート]:[nginx-server側のポート]

nignx:80⇆gunicorn:4000

nginxコンテナの80番ポートに流れてきたリクエストをgunicornコンテナの4000番ポートに流すためには何段階か設定が必要です。
なお、スペースの都合上、関係のある箇所だけ抜き出して書いています。最終形は一番最後にまとめて記載するので、解説に興味ない方は読み飛ばしてください。

docker-compose.yml

gunicornコンテナ(gunicorn-server)を定義して、4000番ポートを解放します。localhostと接続したいわけではないので、portsではなくexposeで指定しています。
※参照 Docker-docs-ja expose

docker-compose.yml
services:
  nginx-server:
    #(略)
  gunicorn-server:
    expose:
     - "4000"

nginx.conf

upstreamブロック内でnginxからリクエストを受け流す先のサーバーを定義します。gunicorn-serverの4000番ポートを解放するよう設定したので、server gunicorn-server:4000;と書きます。
serverブロック内で、nginxの80番ポートで受けたリクエストを、upstreamで定義したサーバーに流すよう設定しています。
(ここのlocation部分を色々いじると、リクエストURLに応じて受け流す先のサーバーを制御できるようになるっぽいです。詳細は「nginx連載5回目: nginxの設定、その3 - locationディレクティブ」を参照。)

nginx.conf
http {
    upstream application {
        server gunicorn-server:4000;
    }
    server {
        listen 80;
        location / {
            proxy_pass http://application/;
        }
    }
}

run.py

flaskのデフォルトポートは5000番になっているので、4000番で受けるよう変更します。(※4000番にした意図は特にありません。適当です。デフォルトの5000番のままでいいと思います。)
あと、gunicornを介してリクエストを受け取るために、host="0.0.0.0"を指定します。
※参考 docker-composeでgunicorn+nginx+flaskを動かしてみた話 - ハマったポイント①:Flaskのサーバーはデフォルトだと公開されてない

run.py
from app.app import app

if __name__ == "__main__":
    app.run(host="0.0.0.0",port=4000)

gunicorn⇆postgres:5432

gunicorn(flask)とpostgresの通信にも何段階か設定が必要です。

docker-compose.yml

postgersコンテナ(postgres-server)を定義して、5432番ポートを解放します。localhostと接続したいわけではないので、portsではなくexposeで指定しています。
また、postgresに接続するためのユーザ名とパスワードをenvironmentで定義します。(認証情報なので、ハードコーディングしないで、別の場所に格納した方がベターかもしれません。)

docker-compose.yml
services:
  nginx-server:
    #(略)
  gunicorn-server:
    #(略)
  postgres-server:
    expose:
     - "5432"
    environment:
     - POSTGRES_USER=[ユーザ名]
     - POSTGRES_PASSWORD=[パスワード]

models.py

先ほど定義した[ユーザ名][パスワード]を使用して、app.config['SQLALCHEMY_DATABASE_URI']にpostgresへの接続情報を記載します。
末尾の/tutorial_blogは、tutorial_blog DBへの接続を定義しています。tutorial_blog DBをPostgres内に作成する部分については後述します。

models.py
from flask_sqlalchemy import SQLAlchemy
from app.app import app

app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://[ユーザ名]:[パスワード]@postgres-server:5432/tutorial_blog'
db = SQLAlchemy(app)

postgres⇆databaseボリューム

postgresコンテナだけだと、コンテナを削除した際にデータが消滅してしまうので、コンテナ外の「ボリューム」と呼ばれる領域にデータを格納する必要があります。一番下のvolumes:でdatabaseボリュームを使用することを宣言し、postgres-server:内のvolumes:で、databaseボリュームと、postgresのデータ格納領域である/var/lib/postgresql/dataを繋げています。
※参考 Docker、ボリューム(Volume)について真面目に調べた

docker-compose.yml
services:
  nginx-server:
    #(略)
  gunicorn-server:
    #(略)
  postgres-server:
    #(略)
    volumes:
      - database:/var/lib/postgresql/data
volumes:
  database:
    driver: local

postgresコンテナの設定

Postgres起動時処理

Postgresを起動時に、コンテナ内の/docker-entrypoint-initdb.d以下に置かれているファイルが実行されます。そこにローカルの/postgres/initdbをマウントしておいて、initdb以下に実行させたい処理を書きます。
※参考 dockerでPostgreSQLのコンテナ作成と初期化

docker-compose.yml
services:
  nginx-server:
    #(略)
  gunicorn-server:
    #(略)
  postgres-server:
    #(略)
    volumes:
      - ./postgres/initdb:/docker-entrypoint-initdb.d
      - #(略)

今回はtutorial_blog DBをPostgresに(無ければ)作る、という処理を初期化処理として組み込みたいため、createdb.sqlに、そのSQL文を記載して、initdb下に格納しておきます。

createdb.sql
create database tutorial_blog

Dockerfile

postgres/Dockerfileに、Dockerイメージ作成のためのコマンドを書いていきます。
Postgresコンテナはデフォルトのまま利用するので、参照元のイメージ指定だけ行います。

postgres/Dockerfile
FROM postgres

また、docker-compose.yml側で、どのDockerfileを利用してイメージのビルドを行うか定義します。

docker-compose.yml
services:
  nginx-server:
    #(略)
  gunicorn-server:
    #(略)
  postgres-server:
    build: ./postgres
    #(略)

gunicornコンテナの設定

flaskアプリファイルのマウント

ローカルでの開発物をgunicorn-serverにマウントして、コンテナ内でも使えるようにします。
今回のflaskアプリでは、依存パッケージを記載しているPipfilePipfile.lock、アプリ本体であるapp/以下全てのファイル、アプリ起動用のrun.pyをコンテナ側でも使いたいので、この4つをコンテナ側の/var/www/以下にマウントしていきます。

docker-compose.yml
services:
  nginx-server:
    #(略)
  gunicorn-server:
    #(略)
    volumes:
     - ./Pipfile:/var/www/Pipfile
     - ./Pipfile.lock:/var/www/Pipfile.lock
     - ./app:/var/www/app/
     - ./run.py:/var/www/run.py
  postgres-server:
    #(略)

Dockerfile

app/Dockerfileに、Dockerイメージ作成とコンテナ起動時処理のためのコマンドを書いていきます。

app/Dockerfile
# 参照元イメージの指定
FROM python:3.7 
# ワーキングディレクトリの指定
WORKDIR /var/www
# コンテナ起動時の実行コマンド
CMD ["bash","-c","pip install pipenv && pipenv install --system && gunicorn run:app -b 0.0.0.0:4000"]

CMDにコンテナ起動時の実行コマンドを記載しています。
(※本当はCMDとENTRYPOINTの違いを理解しなきゃなんだろうけど、一旦これで動いたので。詳細はこちら「DockerfileのCMDとENTRYPOINTを改めて解説する」を参照。)
コンテナ起動後にやりたいことは、
1. pipenvのインストール
2. 依存パッケージのインストール
3. gunicornを介してのアプリ起動
なので、それらを順次行えるようにコマンドを記載しています。コンテナの中で以下のコマンドを実行するイメージですね。

$ pip install pipenv
$ pipenv install --system
$ gunicorn run:app -b 0.0.0.0:4000

pipenv install --systemでは、PipfilePipfile.lockから、依存パッケージのインストールを行なっています。コンテナ内でわざわざpython仮想環境を立てる必要はないので、--systemをつけて、コンテナ内に直接パッケージのインストールを行なっています。
gunicorn run:appで、run.pyapp変数を渡してgunicornを介してのflaskアプリ起動を行なっています。その際の-b 0.0.0.0:4000オプションで、gunicornで受け入れるポートを指定しています。
※参考 Running Gunicorn
※参考 docker-composeでgunicorn+nginx+flaskを動かしてみた話 - ハマったポイント②:gunicorn起動にbindすべし

また、docker-compose.yml側で、どのDockerfileを利用してイメージのビルドを行うか定義します。

docker-compose.yml
services:
  nginx-server:
    #(略)
  gunicorn-server:
    build: ./app
    #(略)
  postgres-server:
    #(略)

db.create_all()

models.pyで定義されたテーブル/カラム情報をもとに、SQLAlchemyのcreate_all()を走らせることで、postgresのtutorial_blog DBにテーブル/カラムの初期設定を行います。
gunicorn run:appで、app.pyが実行されるので、その中にcreate_all()を仕込んでおきます。

models.py
from flask_sqlalchemy import SQLAlchemy
from app.app import app
db = SQLAlchemy(app)
app.py
from flask import Flask
app = Flask(__name__)
from app.models import db
db.create_all()
db.session.commit()

nginxコンテナの設定

nginx.confのマウント

ローカルのnginx/nginx.confに格納しているnginx設定ファイルをコンテナ内でも使えるようにするため、マウント設定を行います。

docker-compose.yml
services:
  nginx-server:
    #(略)
    volumes:
     - ./nginx/nginx.conf:/etc/nginx/nginx.conf
  gunicorn-server:
    #(略)
  postgres-server:
    #(略)

Dockerfile

nginx/Dockerfileに、Dockerイメージ作成とコンテナ起動時処理のためのコマンドを書いていきます。

nginx/Dockerfile
# 参照元イメージの指定
FROM nginx
# コンテナ起動時の実行コマンド
CMD ["nginx", "-g", "daemon off;","-c","/etc/nginx/nginx.conf"]

コンテナ起動後に以下のコマンドを実行しています。

$ nignx -g daemon off; -c /etc/nginx/nginx.conf

nginxをバックグラウンド実行するとコンテナが停止してしまうようなので、-g daemon off;で、フォアグラウンド実行を指定しています。
※参考 Docker 事始め - dockerハマりポイント
また、-c /pass/to/configfileで、nginx設定ファイルの指定を行なっています。
※参考 CommandLine | NGINX

さらに、docker-compose.yml側で、どのDockerfileを利用してイメージのビルドを行うか定義します。

docker-compose.yml
services:
  nginx-server:
    build: ./nginx
    #(略)
  gunicorn-server:
    #(略)
  postgres-server:
    #(略)

コンテナ起動順序の指定

postgresコンテナ→gunicornコンテナ→nginxコンテナの順に起動したいので(nginxコンテナよりgunicornコンテナが先にたってないとupstream指定ができない、gunicornコンテナよりpostgresコンテナが先に立ってないとpostgres接続ができない)、docker-compose.ymlに起動順序を記載していきます。
depends_onを記載すると、指定されたコンテナが起動してから自分のコンテナを起動する、という制御をかけることができます。

docker-compose.yml
services:
  nginx-server:
    #(略)
    depends_on:
     - gunicorn-server
  gunicorn-server:
    #(略)
    depends_on:
     - postgres-server
  postgres-server:
    #(略)

コンテナの起動・動作確認・停止・削除

本当は公式ドキュメント読み込まないといけないところなんですけど、時間がなかったので日本語でまとまっているこちら「docker-compose コマンドまとめ」を参考にさせていただきました。

dockerイメージのビルド

$ docker-compose build

コンテナの起動

$ docker-compose up -d

ブラウザ表示確認

ブラウザでlocalhostにアクセスすると、メインページが表示されるはずです。
スクリーンショット 2019-07-28 18.24.45.png

コンテナの停止とdockerイメージ削除

$ docker-compose down --rmi all

dockerイメージ一覧の確認

$ docker images

コンテナ一覧の確認

$ docker ps -a

ボリューム一覧の確認

$ docker volume ls

各コンテナのログ取得

$ docker logs [コンテナ名]

最終的なファイル内容

docker-compose.yml

docker-compose.yml
version: "3"
services:
  nginx-server:
    build: ./nginx
    volumes:
     - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    ports:
     - 80:80
    depends_on:
     - gunicorn-server
  gunicorn-server:
    build: ./app
    volumes:
     - ./Pipfile:/var/www/Pipfile
     - ./Pipfile.lock:/var/www/Pipfile.lock
     - ./app:/var/www/app/
     - ./run.py:/var/www/run.py
    expose:
     - "4000"
    depends_on:
     - postgres-server
  postgres-server:
    build: ./postgres
    expose:
     - "5432"
    environment:
     - POSTGRES_USER=user
     - POSTGRES_PASSWORD=password
    volumes:
      - ./postgres/initdb:/docker-entrypoint-initdb.d
      - database:/var/lib/postgresql/data
volumes:
  database:
    driver: local

nginx/Dockerfile

nginx/Dockerfile
FROM nginx
CMD ["nginx", "-g", "daemon off;","-c","/etc/nginx/nginx.conf"]

app/Dockerfile

app/Dockerfile
FROM python:3.7
WORKDIR /var/www
CMD ["bash","-c","pip install pipenv && pipenv install --system && gunicorn run:app -b 0.0.0.0:4000"]

postgres/Dockerfile

postgres/Dockerfile
FROM postgres

nginx.conf

解説した部分以外はこちら「Flask+uwsgi+nginxの環境が作りたい?それ、Dockerなら1コマンドで出来るよ。」をかなり参考にしました。

nginx.conf
user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    upstream application {
        server gunicorn-server:4000;
    }
    server {
        listen 80;
        charset utf-8;
        location / {
            proxy_pass http://application/;
        }
    }
}

おわりに

元となるdockerイメージがあるとはいえ結構自前で設定しなきゃいけない部分が多かったので、今までherokuさんがよしなにやってくれていたWebサーバ(nginx)やDBサーバ(postgres)、wsgi(gunicorn)周りがどう動いているのかちょっとだけ理解できました。
今後の方向性としては
1. 他のDockerミドルウェア/アプリと繋ぐ(とりあえずElasticSearchを使ってみたい)
2. クラウドサーバにデプロイしてサービス公開(EC2に乗せてみたい)
3. コンテナオーケストレーション(kubernetes使ってみたい)
という感じで進めたいと思います!

参考まとめ

Docker-docs-ja expose
nginx連載5回目: nginxの設定、その3 - locationディレクティブ
docker-composeでgunicorn+nginx+flaskを動かしてみた話
Docker、ボリューム(Volume)について真面目に調べた
DockerfileのCMDとENTRYPOINTを改めて解説する
dockerでPostgreSQLのコンテナ作成と初期化
Running Gunicorn
Docker 事始め
CommandLine | NGINX
docker-compose コマンドまとめ
Flask+uwsgi+nginxの環境が作りたい?それ、Dockerなら1コマンドで出来るよ。

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

docker-composeを使ってVeu.jsのプロジェクトを作成して、Dockerで動かしてみた

docker-composeを使ってVeu.jsのプロジェクトを作成して、Dockerで動かしてみました。

プロジェクトを作成するディレクトリを作成する

directory
/hoge_directory

プロジェクトを作成するためのdocker-compose.ymlを作成する

directory
/hoge_directory
    |_ docker-compose.yml
docker-compose.yml
version: '3'
services:
  node:
    image: node:12.7.0-alpine
    volumes:
      - .:/vuejs

今回はコンテナ内で作成したVue.jsプロジェクトを、ホストに同期させて作るので、
ホスト側のhoge_directoryとコンテナ内の/vuejsをマウントする

    volumes:
      - .:/vuejs

docker-composeでサービスを起動して、コンテナ内に入る

sh
$ docker-compose run node sh

マウントされている/vuejsに移動する

sh
/ # cd vuejs/

Vue CLIをインストールする

今回はVue CLIを使用して、プロジェクトを作成するので、Vue CLIをインストールする

sh
/vuejs # yarn global add @vue/cli

Vue.jsのプロジェクトを作成する

sh
/vuejs # vue create .

上記のコマンドを実行すると、対話式でプロジェクトの設定をしていく

YESを選択
?  Your connection to the default yarn registry seems to be slow.
   Use https://registry.npm.taobao.org for faster installation? (Y/n) Y
YESを選択
? Generate project in current directory? (Y/n) Y
defaultを選択
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint) 
  Manually select features
Yarnを選択
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn 
  Use NPM 

コンテナ内と、ホスト側に、プロジェクトが作成される

コンテナ
/vuejs
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock
ホスト
/hoge_directory
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock

プロジェクトの作成完了!!!

dockerVue.jsを動かす

Dockerfileを作成する

directory
/hoge_directory
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock
    |_ Dockerfile <- 作成
Dockerfile
FROM node:12.7.0-alpine

WORKDIR /myapp

COPY package.json ./
COPY yarn.lock ./

RUN yarn install

docker-compose.ymlを修正する

docker-compose.yml
version: '3'
services:
  view:
    build: .
    command: yarn run serve
    volumes:
      - .:/myapp
      - /myapp/node_modules
    ports:
      - "8000:8080"

Vue.jsプロジェクトをマウントした場合に、
コンテナ側のnode_modulesが上書きされて、削除される場合があるので、
マウントされないようにする

volumes:
      - ./vuejs:/myapp
      - /myapp/node_modules <- マウントで上書きされなくなる

(プロジェクトが作成される時に作成される.gitignoreでは、
node_modulesはデフォルトで無視されているので、Gitで共有していると、
コンテナが立ち上がらなくなる)

サービスを起動して、コンテナを立ち上げる

sh
$ docker-compose up -d

アクセスする

URL
http://localhost:8000/

スクリーンショット 2019-07-28 13.19.29.png

終わり

マウントした時に、node_modulesが上書きされて、削除されるのは、
なかなかハマりました...

https://github.com/tubutubumustard/vuejs_docker

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

docker-composeを使ってVue.jsのプロジェクトを作成して、Dockerで動かしてみた

docker-composeを使ってVue.jsのプロジェクトを作成して、Dockerで動かしてみました。

プロジェクトを作成するディレクトリを作成する

directory
/hoge_directory

プロジェクトを作成するためのdocker-compose.ymlを作成する

directory
/hoge_directory
    |_ docker-compose.yml
docker-compose.yml
version: '3'
services:
  node:
    image: node:12.7.0-alpine
    volumes:
      - .:/vuejs

今回はコンテナ内で作成したVue.jsプロジェクトを、ホストに同期させて作るので、
ホスト側のhoge_directoryとコンテナ内の/vuejsをマウントする

    volumes:
      - .:/vuejs

docker-composeでサービスを起動して、コンテナ内に入る

sh
$ docker-compose run node sh

マウントされている/vuejsに移動する

sh
/ # cd vuejs/

Vue CLIをインストールする

今回はVue CLIを使用して、プロジェクトを作成するので、Vue CLIをインストールする

sh
/vuejs # yarn global add @vue/cli

Vue.jsのプロジェクトを作成する

sh
/vuejs # vue create .

上記のコマンドを実行すると、対話式でプロジェクトの設定をしていく

YESを選択
?  Your connection to the default yarn registry seems to be slow.
   Use https://registry.npm.taobao.org for faster installation? (Y/n) Y
YESを選択
? Generate project in current directory? (Y/n) Y
defaultを選択
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint) 
  Manually select features
Yarnを選択
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn 
  Use NPM 

コンテナ内と、ホスト側に、プロジェクトが作成される

コンテナ
/vuejs
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock
ホスト
/hoge_directory
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock

プロジェクトの作成完了!!!

dockerVue.jsを動かす

Dockerfileを作成する

directory
/hoge_directory
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock
    |_ Dockerfile <- 作成
Dockerfile
FROM node:12.7.0-alpine

WORKDIR /myapp

COPY package.json ./
COPY yarn.lock ./

RUN yarn install

docker-compose.ymlを修正する

docker-compose.yml
version: '3'
services:
  view:
    build: .
    command: yarn run serve
    volumes:
      - .:/myapp
      - /myapp/node_modules
    ports:
      - "8000:8080"

Vue.jsプロジェクトをマウントした場合に、
コンテナ側のnode_modulesが上書きされて、削除される場合があるので、
マウントされないようにする

volumes:
      - ./vuejs:/myapp
      - /myapp/node_modules <- マウントで上書きされなくなる

(プロジェクトが作成される時に作成される.gitignoreでは、
node_modulesはデフォルトで無視されているので、Gitで共有していると、
コンテナが立ち上がらなくなる)

サービスを起動して、コンテナを立ち上げる

sh
$ docker-compose up -d

アクセスする

URL
http://localhost:8000/

スクリーンショット 2019-07-28 13.19.29.png

終わり

マウントした時に、node_modulesが上書きされて、削除されるのは、
なかなかハマりました...

https://github.com/tubutubumustard/vuejs_docker

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

DockerのみでつくるRailsプロジェクト

概要

Railsプロジェクトを作成する際にDocker環境があるのにわざわざローカル環境にRubyを入れて…は効率が悪すぎるので、Rubyコンテナを使用してRailsプロジェクトを作成しました。
忘備録に手順をまとめたので同じようにRailsプロジェクトを作成したい方の助けになればいいと思います。

環境

  • macOS Mojave 10.14
  • Docker version 18.09.2, build 6247962

rubyコンテナの取得

DockerHubよりRubyイメージを取得

$ docker pull ruby:2.6.3
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ruby 2.6.3 f1c13927d193 13 days ago 870MB

Gemfileの生成

Rubyイメージからコンテナを作成し、Gemfileを生成する。

// コンテナの起動
$ docker run --rm -v `pwd`:/myapp -w /myapp -it ruby:2.6.3 bash
// オプション
--rm: 実行後のコンテナを削除
-v:   共有ディレクトリの設定
-w:   ワーキングディレクトリの設定
-it:  コンテナをフォアグラウンドで実行

// Gemfileの生成
root@a1eeb5367697:/myapp# bundle init
Writing new Gemfile to /myapp/Gemfile

Gemfileの編集

Gemfileを編集し、Railsをインストールするように変更する。

Gemfile
- # gem "rails"
+ gem "rails"

Dockerfile、docker-compose.ymlの作成

コンテナを作成するDockerfileとdocker-compose.ymlを作成する。
各ファイルは下記のようにディレクトリを作成し、配置する。

ディレクトリ構成

├ docker-compose.yml
└ docker
  ├ mysql
  │  ├ volumes ← DB永続化用ディレクトリ
  │  └ password.env
  └ rails
     └ Dockerfile

ファイル内容

Dockerfile
FROM ruby:2.6.3
ENV LANG C.UTF-8

RUN set -x && \
    : "前提パッケージのインストール" && \
    apt-get update -qq && \
    apt-get install -y \
        build-essential \
        mysql-client \
        nodejs

RUN set -x && \
    : "パッケージのインストール" && \
    gem install bundler

WORKDIR /tmp
ADD Gemfile Gemfile
ADD Gemfile.lock Gemfile.lock
RUN bundle install

ENV APP_HOME /myapp
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD . $APP_HOME
docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7.26
    ports:
      - "3306:3306"
    volumes:
      - ./docker/mysql/volumes:/var/lib/mysql
    env_file: ./docker/mysql/password.env
  web:
    build:
      context: .
      dockerfile: ./docker/rails/Dockerfile
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - "3000:3000"
    volumes:
      - .:/myapp
    environment:
      RAILS_ENV: development
    env_file: ./docker/mysql/password.env
    depends_on:
      - db

DBのパスワードを設定

password.env
MYSQL_ROOT_PASSWORD=password

Railsプロジェクトの生成

Dockerfile、docker-compose.ymlで定義したコンテナのビルドを行い、コンテナにログインする。

// コンテナビルド
$ docker-compose build

// コンテナにログイン
$ docker-compose up -d
$ docker-compose exec web bash
// オプション
-d: バックグラウンド実行

// railsプロジェクトの生成
root@477e08f00455:/var/www/CleanManager# rails new . -d mysql -BT
// オプション
-d: DBをmysqlに設定
-B: bundle installを省略
-T: テストファイルの作成を省略

// パッケージのインストール
root@477e08f00455:/var/www/CleanManager# bundle install

railsアプリの起動

コンテナの再起動を行う。
docker-compose.ymlにビルドインサーバを起動するコマンドを記述しているため、別途起動するコマンドを実行する必要はない。
再起動後、ブラウザで http://localhost:3000 にアクセスし起動していることを確認する。

root@477e08f00455:/var/www/CleanManager# exit
$ docker-compose down
$ docker-compose up -d

まとめ

Docker初心者だったので、よくわからないことがありましたが、なんとか作成することができました。
DBをMySQLからPostgreSQLに変更したかったのですが、PostgreSQLコンテナが起動直後に落ちてしまったのでMySQLで妥協しました。
今後も原因を探して判明しだい、再度記事にしたいと思います。
間違い等ありましたら、コメントから修正お願いします。

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

Python ✖︎ Flask ✖︎ Webアプリ(4)DBに接続して操作してみよう

目的

  • Flask で Postgresql に接続
  • DB にレコードを登録できること
  • DB からレコードを取得できること

本編

環境準備

python のパッケージを追加

requirements.txt
flask
sqlalchemy
psycopg2

上記をpip install -r requirements.txt でインストール

ポイント

sqlalchemyは python の ORM ライブラリ(簡単に言うとDB 操作は sqlalchemy が担当するよ)

psycopg2は flask と postgresql を繋いでくれる役割

インストールしたパッケージを一括でアンインストールする(必要があれば)
  • pip でインストールしたパッケージの一覧を取得
$ pip freeze > piplist.txt
  • 一括でアンインストール
$ pip uninstall -y -r piplist.txt

前回まで

Python ✖︎ Flask ✖︎ Webアプリ(3)Docker登場 DBの準備
Python ✖︎ Flask ✖︎ Webアプリ(2)HTMLの表示とメソッドとパラメータの受け取りかた
Python ✖︎ Flask ✖︎ Webアプリ(1)こんにちは世界

フォルダ構成

.
├── README.md
├── docker-compose.yml
├── form.html
├── postgresql
│   └── init
│       ├── 1_create_db.sql
│       └── 2_create_table.sh
├── requirements.txt
├── src
│   ├── UserModel.py
│   ├── main.py
│   ├── setting.py
│   └── templates
│       └── hello.html
└── test.http

DB接続の準備

setting.py
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
import psycopg2

# postgresqlのDBの設定
DATABASE = "postgresql://postgres:@192.168.1.19:5432/flask_tutorial"

# Engineの作成
ENGINE = create_engine(
    DATABASE,
    encoding="utf-8",
    # TrueにするとSQLが実行される度に出力される
    echo=True
)

# Sessionの作成
session = scoped_session(
    # ORM実行時の設定。自動コミットするか、自動反映するなど。
    sessionmaker(
        autocommit=False,
        autoflush=False,
        bind=ENGINE
    )
)

# modelで使用する
Base = declarative_base()
Base.query = session.query_property()

ポイント

  • DB の接続先情報

    DATABASE = "postgresql://postgres:@192.168.1.19:5432/flask_tutorial

    DATABASE = "postgresql://{DBのユーザ}:{DBのパスワード}@{url}:{ポート番号}/{DB名}

    今回のDBは前回用意したDBをそのまま利用

    {url}は自分のPCのIPを入力

  • Engine 作成

ENGINE = create_engine(
    DATABASE,
    encoding="utf-8",
    # TrueにするとSQLが実行される度に出力される
    echo=True
)

Engine はDBにアクセスするための土台なんだと覚えとけば、とりあえずOK

  • Session作成
session = scoped_session(
    # ORM実行時の設定。自動コミットするか、自動反映するなど。
    sessionmaker(
        autocommit=False,
        autoflush=False,
        bind=ENGINE
    )
)

SessionはflaskとDBとのやり取りを全て担当してくれるもの

データを挿入するテーブルを準備

2_create_table.sh
#!/bin/bash
psql -U postgres -d flask_tutorial << "EOSQL"
CREATE TABLE users (
        id SERIAL NOT NULL, 
        name VARCHAR(200), 
        created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, 
        updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, 
        PRIMARY KEY (id)
);
EOSQL
UserModel.py
from datetime import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DateTime
from setting import Base
from setting import ENGINE

class User(Base):
    """
    UserModel
    """

    __tablename__ = 'users'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(200))
    created_at = Column(DateTime, default=datetime.now, nullable=False)
    updated_at = Column(DateTime, default=datetime.now, nullable=False)

    def __init__(self, name):
        self.name = name

if __name__ == "__main__":
    Base.metadata.create_all(bind=ENGINE)

ポイント

  • DBのDockerコンテナを初めて起動した際に、2_create_table.shでUserテーブルを作成する
    ※ DBが一度作成されている場合は、/Users/${USER}/Volumes/flask_tutorial/postgresを削除する
  • flask側にDB上に、どんなテーブルがあるのかをsqlarchemyを使用して定義してあげる

DB 確認

  • コンテナを起動
$ docker-compose up -d
Creating network "flask-tutorial_default" with the default driver
Creating flask_tutorial_postgresql ... done
Creating flask_tutorial_pgadmin4   ... done
  • pgadminでUserテーブルが作成されていることを確認
スクリーンショット 2019-07-28 14.29.32.png

DB操作準備

main.py
from flask import Flask, request, render_template
from UserModel import User
from setting import session
from sqlalchemy import *
from sqlalchemy.orm import *

# appという名前でFlaskのインスタンスを作成
app = Flask(__name__)

# 登録処理
@app.route('/', methods=["POST"])
def register_record():

    name = request.form['name']

    session.add(User(name))

    session.commit()

    return render_template("hello.html", name=name, message="登録完了しました!")

# 取得処理
@app.route('/', methods=["GET"])
def fetch_record():

    name = request.args.get('name')

    db_user = session.query(User.name).\
        filter(User.name == name).\
        all()

    if len(db_user) == 0:
        message = "登録されていません。"
    else:
        message = "登録されています。"

    return render_template("hello.html", name=name, message=message)

if __name__ == '__main__':
    app.run()


ポイント

  • 操作に必要なものをインポート

    • 操作対象のテーブル
    • DBの操作を行うのでsessionが必要
from UserModel import User
from setting import session
from sqlalchemy import *
from sqlalchemy.orm import *
  • 登録処理
# 登録処理
@app.route('/', methods=["POST"])
def register_record():

    name = request.form['name']

    session.add(User(name))

    session.commit()

    return render_template("hello.html", name=name, message="登録完了しました!")

実際に登録している箇所は以下

    session.add(User(name))

    session.commit()

session.addでINSERT文を実行

session.commit()コミットしてる

  • 取得処理
# 取得処理
@app.route('/', methods=["GET"])
def fetch_record():

    name = request.args.get('name')

    db_user = session.query(User.name).\
        filter(User.name == name).\
        all()

    if len(db_user) == 0:
        message = "登録されていません。"
    else:
        message = "登録されています。"

    return render_template("hello.html", name=name, message=message)

取得処理は、以下

    db_user = session.query(User.name).\
        filter(User.name == name).\
        all()

session.query(User.name)で取得したいテーブル.列名

filter(User.name == name)はWHERE句

all()でクエリを実行

※ 今回は単純なSELECT文のみ、テーブル結合などもできるので必要に応じて適宜調べてください。

DB操作確認

  • コンテナを起動
 $ docker-compose up -d
 Creating network "flask-tutorial_default" with the default driver
 Creating flask_tutorial_postgresql ... done
 Creating flask_tutorial_pgadmin4   ... done
  • flaskを起動
$ python src/main.py
 * Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
  • form.htmlで確認

次回

  • nginxのdockerコンテナを用意して、静的なページをflaskから切り離す
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python ✖︎ Flask ✖︎ Webアプリ(4)DBに接続

目的

  • Flask で Postgresql に接続
  • DB にレコードを登録できること
  • DB からレコードを取得できること

本編

環境準備

python のパッケージを追加

requirements.txt
flask
sqlalchemy
psycopg2

上記をpip install -r requirements.txt でインストール

ポイント

sqlalchemyは python の ORM ライブラリ(簡単に言うとDB 操作は sqlalchemy が担当するよ)

psycopg2は flask と postgresql を繋いでくれる役割

インストールしたパッケージを一括でアンインストールする(必要があれば)
  • pip でインストールしたパッケージの一覧を取得
$ pip freeze > piplist.txt
  • 一括でアンインストール
$ pip uninstall -y -r piplist.txt

前回まで

Python ✖︎ Flask ✖︎ Webアプリ(3)Docker登場 DBの準備
Python ✖︎ Flask ✖︎ Webアプリ(2)HTMLの表示とメソッドとパラメータの受け取りかた
Python ✖︎ Flask ✖︎ Webアプリ(1)こんにちは世界

フォルダ構成

.
├── README.md
├── docker-compose.yml
├── form.html
├── postgresql
│   └── init
│       ├── 1_create_db.sql
│       └── 2_create_table.sh
├── requirements.txt
├── src
│   ├── UserModel.py
│   ├── main.py
│   ├── setting.py
│   └── templates
│       └── hello.html
└── test.http

DB接続の準備

setting.py
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
import psycopg2

# postgresqlのDBの設定
DATABASE = "postgresql://postgres:@192.168.1.19:5432/flask_tutorial"

# Engineの作成
ENGINE = create_engine(
    DATABASE,
    encoding="utf-8",
    # TrueにするとSQLが実行される度に出力される
    echo=True
)

# Sessionの作成
session = scoped_session(
    # ORM実行時の設定。自動コミットするか、自動反映するなど。
    sessionmaker(
        autocommit=False,
        autoflush=False,
        bind=ENGINE
    )
)

# modelで使用する
Base = declarative_base()
Base.query = session.query_property()

ポイント

  • DB の接続先情報

    DATABASE = "postgresql://postgres:@192.168.1.19:5432/flask_tutorial

    DATABASE = "postgresql://{DBのユーザ}:{DBのパスワード}@{url}:{ポート番号}/{DB名}

    今回のDBは前回用意したDBをそのまま利用

    {url}は自分のPCのIPを入力

  • Engine 作成

ENGINE = create_engine(
    DATABASE,
    encoding="utf-8",
    # TrueにするとSQLが実行される度に出力される
    echo=True
)

Engine はDBにアクセスするための土台なんだと覚えとけば、とりあえずOK

  • Session作成
session = scoped_session(
    # ORM実行時の設定。自動コミットするか、自動反映するなど。
    sessionmaker(
        autocommit=False,
        autoflush=False,
        bind=ENGINE
    )
)

SessionはflaskとDBとのやり取りを全て担当してくれるもの

データを挿入するテーブルを準備

2_create_table.sh
#!/bin/bash
psql -U postgres -d flask_tutorial << "EOSQL"
CREATE TABLE users (
        id SERIAL NOT NULL, 
        name VARCHAR(200), 
        created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, 
        updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, 
        PRIMARY KEY (id)
);
EOSQL
UserModel.py
from datetime import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DateTime
from setting import Base
from setting import ENGINE

class User(Base):
    """
    UserModel
    """

    __tablename__ = 'users'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(200))
    created_at = Column(DateTime, default=datetime.now, nullable=False)
    updated_at = Column(DateTime, default=datetime.now, nullable=False)

    def __init__(self, name):
        self.name = name

if __name__ == "__main__":
    Base.metadata.create_all(bind=ENGINE)

ポイント

  • DBのDockerコンテナを初めて起動した際に、2_create_table.shでUserテーブルを作成する
    ※ DBが一度作成されている場合は、/Users/${USER}/Volumes/flask_tutorial/postgresを削除する
  • flask側にDB上に、どんなテーブルがあるのかをsqlarchemyを使用して定義してあげる

DB 確認

  • コンテナを起動
$ docker-compose up -d
Creating network "flask-tutorial_default" with the default driver
Creating flask_tutorial_postgresql ... done
Creating flask_tutorial_pgadmin4   ... done
  • pgadminでUserテーブルが作成されていることを確認
スクリーンショット 2019-07-28 14.29.32.png

DB操作準備

main.py
from flask import Flask, request, render_template
from UserModel import User
from setting import session
from sqlalchemy import *
from sqlalchemy.orm import *

# appという名前でFlaskのインスタンスを作成
app = Flask(__name__)

# 登録処理
@app.route('/', methods=["POST"])
def register_record():

    name = request.form['name']

    session.add(User(name))

    session.commit()

    return render_template("hello.html", name=name, message="登録完了しました!")

# 取得処理
@app.route('/', methods=["GET"])
def fetch_record():

    name = request.args.get('name')

    db_user = session.query(User.name).\
        filter(User.name == name).\
        all()

    if len(db_user) == 0:
        message = "登録されていません。"
    else:
        message = "登録されています。"

    return render_template("hello.html", name=name, message=message)

if __name__ == '__main__':
    app.run()


ポイント

  • 操作に必要なものをインポート

    • 操作対象のテーブル
    • DBの操作を行うのでsessionが必要
from UserModel import User
from setting import session
from sqlalchemy import *
from sqlalchemy.orm import *
  • 登録処理
# 登録処理
@app.route('/', methods=["POST"])
def register_record():

    name = request.form['name']

    session.add(User(name))

    session.commit()

    return render_template("hello.html", name=name, message="登録完了しました!")

実際に登録している箇所は以下

    session.add(User(name))

    session.commit()

session.addでINSERT文を実行

session.commit()コミットしてる

  • 取得処理
# 取得処理
@app.route('/', methods=["GET"])
def fetch_record():

    name = request.args.get('name')

    db_user = session.query(User.name).\
        filter(User.name == name).\
        all()

    if len(db_user) == 0:
        message = "登録されていません。"
    else:
        message = "登録されています。"

    return render_template("hello.html", name=name, message=message)

取得処理は、以下

    db_user = session.query(User.name).\
        filter(User.name == name).\
        all()

session.query(User.name)で取得したいテーブル.列名

filter(User.name == name)はWHERE句

all()でクエリを実行

※ 今回は単純なSELECT文のみ、テーブル結合などもできるので必要に応じて適宜調べてください。

DB操作確認

  • コンテナを起動
 $ docker-compose up -d
 Creating network "flask-tutorial_default" with the default driver
 Creating flask_tutorial_postgresql ... done
 Creating flask_tutorial_pgadmin4   ... done
  • flaskを起動
$ python src/main.py
 * Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
  • form.htmlで確認

次回

  • nginxのdockerコンテナを用意して、静的なページをflaskから切り離す
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

gRPC UIを使ってみんなが触れるgRPCの遊び場を作りました

gRPCは近年非常によく使われるようになったRPCフレームワーク1ですが、その柔軟なメッセージフォーマットに対応するリッチなGUIクライアントに欠けていました。REST APIでいうPostman的な存在です。このようなツールがなければgRPCを利用した開発が面倒なのですが、その問題は現在においてはほぼ払拭されたといっても過言ではありません。gRPC UIが登場したからです。

(本記事は自分のブログからの転載記事です。)

TL;DR

  • gRPC UIで作成した遊び場はこちらです :point_right: gRPC UI playground
  • gRPC UIはgRPCサーバへの要求と応答がWebで簡単にできるので、今後のgRPCを利用した開発に広く使われるツールとなりそうです
  • gRPC UI playgroundは以下のサービスを利用して、無料で立ち上げました。当面はみんなが遊べるようにしておくつもりです

はじめに

本記事はgRPCのWeb UIであるgRPC UIの紹介記事です。gRPCに興味がある方、gRPCを利用している方を対象にしています。実際にgRPC UIを触れる遊び場も作ったのでgRPCに興味がある方は遊んでいってください。また本記事ではこの遊び場をどうやって作ったのかも簡単に解説します。

gRPCとは

gRPCはGoogleが開発してオープンソースとして公開したRPCフレームワークです。IDL2としてProtocol Buffers3が利用可能です4。gRPCは基本的には以下の図ように単純で、クライアントから要求(Proto Request)を送ってサーバが応答(Proto Response)を返すというものです。クライアントやサーバの記述には、Protocol Buffersが対応している様々な言語(C++, Ruby, Java等)が利用可能です。

What is gRPCより引用

gRPCは上記のように単純な要求/応答型以外にも様々なやりとりに対応できます。具体的には以下の4つです。

  • Unary RPC(単純な要求/応答型)
  • Server streaming RPC(サーバが複数の応答を返すことができる)
  • Client streaming RPC(クライアントが複数の応答を返すことができる)
  • Bidirectional streaming RPC(クライアントとサーバがそれぞれ複数の要求/応答ができる。一般的な双方向通信)

上記のような柔軟な呼び出しはHTTP/25の基盤に支えられて実現されています。

gRPC UIについて

gRPC UIはgRPCサーバとブラウザでやりとりできるツールです。百聞は一見にしかず。以下の画面を御覧ください。

この画面を見て震えたのはやはり要求の入力画面(Request Form)の充実っぷりです。gRPCは自分でデータの型を定義して入れ子のようなメッセージを定義できますが、そのような入力も簡単にできます。上記の図のではtest.TestMessageというメッセージの中にperson(test.Personというメッセージの型)が内包されています。また複数のデータが入力可能なフィールドは「Add Item」で簡単に追加できます。その他の注目すべき点は赤字で説明を入れておいたので参考にしてください。基本的にはgRPC(Protocol Buffers)で定義されている入力形式はほぼ網羅されています。

また、驚いたのはgRPCには基本的なスカラ値(stringint64等)以外にも「Well-Known Types」と呼ばれる型が定義されていますが、gRPC UIにはこれらにもリッチなインタフェースが提供されていたことです。以下の画面はtimestamp型に対するインタフェースです。

またリッチなフォームだけではなく、JSON形式でリクエストを投げることもできます。

JSON形式で便利なのはコピペが容易なところです。また省略されているフィールドは出力されないので見やすくなります。フォーム型の編集画面とも連動しているので、非常に使いやすいです。リクエストは「Invoke」ボタンを押すことでサーバに投げることができます。このボタンはフォーム型のリクエストにも一番下にあります。以下が「Invoke」を押して返ってきた応答になります。

この画面も特に説明がいらないくらい分かりやすいものになっています。gRPC UIで対応できないのは双方向の複雑なやり取りです。これは従来どおりCUI等を利用して行うしかありません。

gRPC UIで遊ぼう! 〜 gRPC UI playground 〜

さて、ここまで来たらgRPC UIで遊んでみたくなったと思います。以下にみんなが遊べるように「遊び場」を立ち上げたのでぜひいろいろ遊んでみてください。

gRPC UIはバックグラウンドで起動しているgRPC UIのテストサーバ(testsvr)とやりとりしています。プロトコルは「test.proto」、サーバの実装は「testsvr.go」に記述されています。実際にgRPC UIを動かしながらソースやIDLを読むとgRPCの理解が深まると思います。

メソッドに関しては「DoManyThings」が全部詰めになっていて、残りのメソッドはそれを機能単位で分割したものになっています。たぶん・・・

grpcui-playgroundの作り方

さて、ここからはおまけです。上記の遊び場(以降、grpcui-playgroundと記載)の構築方法の興味がある方を対象に簡単に説明したいと思います。grpcui-playgroundは3つのサービスを利用して無料で立ち上げました。以下がその構成になります。

上の図をざっくり説明すると、基本的にはDockerを使ってサービス提供しています。一つのコンテナの中にgPPC UIとgRPC Server(testsvr)という二つのプロセスが動いています。一つのコンテナに二つのプロセスはあまりお行儀がよくありませんが、今回は遊び場ということと無料で立ち上げることを重視したのでこのような構成になっています。
利用したコンテナホスティングサービスはArukas6になります。今回はFreeプランを利用しています。Arukasにコンテナイメージを提供するためにはDocker Hubも利用しました。Docker HubにはGitHubと連携しておくとGitHubの変更を検知してコンテナをビルドする機能があるのでそれも利用しています。

Dockerfileを書く

Dockerfileを書くときの注意点は二つです。まず、ビルドイメージを小さくするためにAlpine Linux7をベースイメージにします。次にgRPC UIが提供しているテストサーバ(testsvr)はgoで書かれているのでgoのビルド環境が必要です。ただしgoのビルド環境は動作には必要ないのでマルチステージビルドを活用して、なるべく小さなイメージにするようにしましょう8

Dockerfile
FROM golang:1.12.7-alpine as build-env
MAINTAINER hinastory

WORKDIR /testsvr
COPY testsvr /testsvr
COPY start.sh /start.sh

RUN apk update && apk add --no-cache git

RUN go build

RUN go get -x github.com/fullstorydev/grpcui
RUN go install -x github.com/fullstorydev/grpcui/cmd/grpcui

FROM alpine
WORKDIR /
COPY --from=build-env /testsvr/testsvr /bin/testsvr
COPY --from=build-env /go/bin/grpcui /bin/grpcui
COPY start.sh /start.sh

EXPOSE 8080

ENTRYPOINT [ "/start.sh" ]

GitHubでDockerfileを公開する

ここは特に説明はしませんが、GitHubに公開レジストリを作成し、Dockerfileとtestsvrのソースと起動スクリプトをpushします。pushした自分のリポジトリは以下になります。

Docker Hubでイメージをビルド & 公開する

Docker Hubでイメージをビルドするのには、GitHubと連携しておいたほうが楽です。GitHubと連携しておけばGitHubのレポジトリをDocker HubのUIから選択できるようになり、GitHubにpushするだけでDockerfileをビルドしてくれるようになります。

注意すべき点はDockerイメージのタグの付け方です。デフォルトだとブランチを監視してlatestタグを付けるようになっていますが、Arukasはイメージをキャッシュする場合があるようなのでバージョンが入った適切なタグをつけることが望ましいです。そしてDockerのイメージタグはGitHubのタグと連動しているとよいと思われます。

Docker Hubでその設定をするのは簡単でDockerHubのリポジトリのBuildsの画面からビルドルールを設定でき、Source TypeTagにして、SourceDocker Tagを正規表現で記述することでお望みのタグが構成できると思います。またここでDockerfileの位置やビルドコンテキストも指定可能なので、少し複雑なリポジトリ構成でも対応出来ます。

ここの設定が終わったらGitHubにタグをpushしてビルドが始まるか確認します。基本的には検知はすぐに行われてIn Progressの状態にすぐに変わりますがビルドが終わるまでには時間がかかるので、コーヒーでも飲んでまったりと待ちましょう(笑)。自分のコンテナイメージは以下に公開してあります。

ArukasでDockerコンテナを公開する

最後にArukasuでコンテナを公開します。FreeプランはO.1vCPUと128MB RAMの非力な環境ですが、今回のような遊び場には充分だと思われます。また「転送量課金」がないのでDDoSとかの心配がまったくいらないのも嬉しいところです。もちろん最悪サービスは落とされますが、料金に怯える心配は無いわけです。ちなみにFreeプランでも電話認証とクレジットカードの登録は必須です。このアカウント登録が最大の難関でコンテナの起動は驚くほどあっけなく終わりました。アプリ起動の詳細は「アプリの作成 – Arukas Help Center」を参照してください。以下は起動したコンテナの管理画面です。Endpointはアプリの再起動で変わることが無いURLです。Portはインスタンスの起動毎に変わります。ちなみにgRPC UIは8080ポートでHTTPでサービスを公開していますが、エンドポイントではHTTPSになっているので自動でArukasがHTTPSに包んでくれるみたいです。

まとめ

本記事では、gRPCサーバとブラウザでやり取りできるgRPC UIを紹介しました。gRPC UIは非常に便利なので今後gRPC関連の開発で広く使われていくものと思われます。そして実際にgRPC UIを触れる遊び場を作成して以下に公開しました。

また、おまけとしてその遊び場の作り方を(無料でコンテナサービスを立ち上げる手順)を簡単に説明しました。
本記事がgRPCを理解し、より便利に使えるようになるための一助になれば幸いです。

参考文献


  1. RPC(Remote Procedure Call)は、簡単に言えばプログラムの中から内部の関数を呼ぶのと似たような感覚で、外部のネットワーク上の関数や手続きを呼べるようにする技術のことです。他のRPCにはSOAPやJSON-RPCなどがあります。 

  2. IDLはインタフェース記述言語(Interface Description Language)のことです。簡単に言えば関数呼び出しの宣言部分を定義する際に使う言語です。 

  3. Protocol BuffersはGoogleが開発したシリアライズフォーマットです。IDLは独自の言語でシンプルで分かりやすいのが特徴です。IDLのファイルは.protoの拡張子を持っており、protocというコンパイラを用いてIDLファイルからGo言語やRuby、Python、Java等様々な言語のバインディングを生成できます。現在のProtocol Buffersのバージョンは3になります。 

  4. JSONも利用可能みたいですが、自分は使ったことはありません。 

  5. HTTP2はHTTP/1.1の後継バージョンでRFC7540で定義されています。HTTP/1.1と比べてヘッダーの圧縮やバイナリメッセージ構造、双方向通信のサポート等様々な改善がなされています。 

  6. Arukasはさくらインターネットが提供しているDockerのホスティングサービスです。Arukasを反対から読むと・・・ 

  7. Alpine Linuxは軽量、シンプル、セキュアをコンセプトにしたLinuxディストリビューションです。組み込み系で実績のあるmusl libcとbusyboxをベースにしています。その軽量さからコンテナのベースイメージとしてよく利用されています。 

  8. 最初は無邪気にベースイメージをstretchにしてシングルステージでビルドしたため、イメージのサイズが400MBを超えてしまいました・・・現在のサイズは 18MBです。特にパブリックなレジストリに登録する際はコンテナイメージのサイズに充分気を配り、リソースを無駄にしないように心掛けましょう(自戒)。 

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

【メモ】Rootless Docker

Rootless Mode

Docker 19.03 ではまだ実験的扱いであるが、良い感じ。

https://github.com/moby/moby/blob/ca5aab19b482f27629374cdde4df26b5676e39cb/docs/rootless.md

Security が高まります。

Katacodaで試すとよろしい。
https://www.katacoda.com/courses/docker/rootless

使い方

ざっくりすべて一般ユーザ(rootless)で行う

  • 一般ユーザで入れて(curl -sSL https://get.docker.com/rootless |sh
  • 環境変数セットして
  • rootlessのシェル実行(Daemon起動)して
  • run する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【メモ】VFS Storage Driver

VFS Storage Driver

https://docs.docker.com/storage/storagedriver/vfs-driver/

  • union FSではない
  • 容量とパフォーマンスにデメリットがある
  • CoWは未対応
  • 新しいレイヤーを作るときは「deep copy(オブジェクトとメモリの両方がコピーされる)」である
  • /var/lib/docker/vfs/dir/ に配置されるが、イメージレイヤIDsとの関連性はない
  • どんな backing filesystemでも使える
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker ComposeでGitLabを起動

Docker Composeとは

  • Dockerコンテナの設定をyamlファイルで定義し、構築・管理が行えるツール
    • docker container runコマンドのオプションなどをファイルで定義するイメージ
  • 複数個のコンテナを扱える

メリット

  • 設定をコードで管理できる(IaC)
  • 複数個のコンテナを扱う場合は
    • runコマンドを何回も打たなくて済む
    • コンテナ同士の依存関係をファイルで定義できる

実行環境

  • OS
    • Amazon Linux 2
  • 前提
    • Docker 18.06.1-ceがインストール済み

インストール

  • Dockerエンジンのパッケージには含まれていないので別途インストールが必要
  • Docker for Windows/Macには含まれている
  • 公式ドキュメントに沿って実行

手順

  • 資源をダウンロード
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  • 実行権限を付与
$ sudo chmod +x /usr/local/bin/docker-compose
  • バージョンが表示されれば成功
$ docker-compose version
docker-compose version 1.24.1, build 4667896b
docker-py version: 3.7.3
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.1.0j  20 Nov 2018

実行

yamlファイル

  • 今回は例としてGitLabのコンテナを動かす
docker-compose.yaml
version: '3.7'
services:
  gitLab:
    image: gitlab/gitlab-ce:latest
    ports:
     - "80:80"
    volumes:
     - '/srv/gitlab/config:/etc/gitlab'
     - '/srv/gitlab/logs:/var/log/gitlab'
     - '/srv/gitlab/data:/var/opt/gitlab'
  • version
  • servicesの配下に適当な名前を付与し、その配下に設定を記述する
  • image
    • 起動させるDockerイメージ
  • ports
    • ホスト側とコンテナ側で何番のポートをフォワーディングするかを指定
    • pオプションに該当
  • volumes

    • コンテナからマウントするホストのパスを指定
    • vオプションに該当
  • 上記の設定はdocker container runコマンドの場合は次のコマンドに該当する

$ docker container run gitlab/gitlab-ce:latest -p 80:80 -v /srv/gitlab/config:/etc/gitlab -v /srv/gitlab/logs:/var/log/gitlab -v /srv/gitlab/data:/var/opt/gitlab

実行

  • docker-compose upのコマンドで実行可能
$ docker-compose -f ./docker-compose.yaml up -d
  • f オプションでyamlファイルを指定できるが、カレントパスにdocker-compose.yaml(yml)という名前のファイルがあれば省略可能
    • カレントパス以外のパスにあるファイルや、他の名前が付いているファイルを指定する場合は必須
    • これ以外のdocker-composeコマンドでもファイルを参照するので、基本的にカレントディレクトリにファイルがある状態で操作するべき
  • d オプションでコンテナをデタッチモード(バッククダウンドでの実行)で起動される
  • 以下のコマンドで起動が確認できる
$ docker-compose  ps
         Name                       Command                       State                          Ports
---------------------------------------------------------------------------------------------------------------------
gitlab_gitLab_1          /assets/wrapper                  Up (health: starting)   22/tcp, 443/tcp, 0.0.0.0:80->80/tcp

名前に関して

  • [プロジェクト名] _ [サービス名] _ [採番された番号]で命名される
    • プロジェクト名
      • 環境変数「COMPOSE_PROJECT_NAME」に指定されている値
      • 設定されていない場合はyamlファイルが配置されているフォルダ名が設定される
    • サービス名
      • docker-compose.yamlのservicesで指定した名前
    • 採番された番号
      • スケールする場合にコンテナ毎に採番される
      • スケールしていない場合は1が付与される
  • 参考

停止

  • 以下のコマンドで停止できる
$ docker-compose stop
Stopping gitlab_gitLab_1        ... done

実行(複数コンテナ)

yamlファイル

  • GitLabのCIツールであるGitLab Runnerを同時に構築する
docker-compose.yaml
version: '3.7'
services:
  gitLab:
    image: gitlab/gitlab-ce:latest
    ports:
     - "80:80"
    volumes:
     - '/srv/gitlab/config:/etc/gitlab'
     - '/srv/gitlab/logs:/var/log/gitlab'
     - '/srv/gitlab/data:/var/opt/gitlab'
  gitLab-runner:
    image: gitlab/gitlab-runner:latest
    volumes:
     - '/srv/gitlab-runner/config:/etc/gitlab-runner'
     - '/var/run/docker.sock:/var/run/docker.sock'
    networks:
     mynet:
      ipv4_address: 172.20.0.3
    depends_on:
      - gitLab
  • 同じようにservicesを定義すればよい
  • 今回はgitLab-runnerという名前で追記
  • depends_onを記載することでコンテナ間の依存関係を定義できる
    • GitLabが起動した後にRunnerを起動させたいので、Runnerのdepends_onにGitLabのサービス名を指定しておく

実行

  • 先ほどと同様に起動する
$docker-compose -f ./docker-compose.yaml up -d
Starting gitlab_gitLab_1 ... done
Starting gitlab_gitLab-runner_1 ... done
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DOCKER で ORACLE 12C を起動して PDB に接続するまで

接続には IntelliJ IDEA のプラグイン DBNavigator を使って接続します。

Docker の起動まで

あまりはっきり覚えていませんが・・・ Oracle Database Server Docker Image Documentation からイメージを取得します。

Docker image に Oracle が追加されます。

% docker image ls
REPOSITORY                         TAG                 IMAGE ID            CREATED             SIZE 
store/oracle/database-enterprise   12.2.0.1            12a359cd0528        23 months ago       3.44GB

そして、次のコマンドで docker を起動します。

docker run -it --name oracle-db -p 1521:1521 -p 5500:5500 store/oracle/database-enterprise:12.2.0.1 

Oracle PDB への接続準備

次のコマンドを実行し、 SQLPLUS を起動します。

docker exec -it $CONTAINER_ID bash -c "source /home/oracle/.bashrc; sqlplus /nolog"   
# ORCLCDB に接続します。
## sys ユーザ のパスワードは Oradoc_db1 で、 sysdba として接続します。
SQL> conn sys/Oradoc_db1@ORCLCDB as sysdba

# PDB のセッションに変更します。
SQL> alter session set container=ORCLPDB1

# ユーザを作成します。
SQL> create user developer identified by developer;

# 接続権限をつけます。
SQL> grant create session to developer;

接続確認

接続する場合はサービス名を確認します。
次のコマンドで、 Docker 内 の bash を使います。

docker exec -it  bash -c "source /home/oracle/.bashrc; bash"   

lsnrctr status を実行します。

[oracle@3fda365c7b37 /]$ lsnrctl status

LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 28-JUL-2019 01:43:37

Copyright (c) 1991, 2016, Oracle.  All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=0.0.0.0)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 12.2.0.1.0 - Production
Start Date                28-JUL-2019 01:43:11
Uptime                    0 days 0 hr. 0 min. 26 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Parameter File   /u01/app/oracle/product/12.2.0/dbhome_1/admin/ORCLCDB/listener.ora
Listener Log File         /u01/app/oracle/diag/tnslsnr/3fda365c7b37/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=3fda365c7b37)(PORT=5500))(Security=(my_wallet_directory=/u01/app/oracle/product/12.2.0/dbhome_1/admin/ORCLCDB/xdb_wallet))(Presentation=HTTP)(Session=RAW))
Services Summary...
Service "8eb4210da4b50113e053020011ac5c30.localdomain" has 1 instance(s).
  Instance "ORCLCDB", status READY, has 1 handler(s) for this service...
Service "ORCLCDB.localdomain" has 1 instance(s).
  Instance "ORCLCDB", status READY, has 1 handler(s) for this service...
Service "ORCLCDBXDB.localdomain" has 1 instance(s).
  Instance "ORCLCDB", status READY, has 1 handler(s) for this service...
Service "orclpdb1.localdomain" has 1 instance(s).
  Instance "ORCLCDB", status READY, has 1 handler(s) for this service...
The command completed successfully

下から3行目に orclpdb1.localdomai と書かれているのがわかります。
このサービス名を使ってデータベースに接続します。

DB Navigator の画面で、 次の様に記述して "Test Connection" ボタン をクリックします。

Name Value
Host localhost
Database orclpdb1.localdomain (Service name)
User developer
Password developer

image.png

接続に成功します。

image.png

その他権限設定 (必要があれば)

SQL> grant create table to developer;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

dockerでERROR: for mysql Cannot start service mysql: driver failed programming external connectivity on endpoint test-mysqlが出た時の対処

docker-compose run web rails new . --force --database=mysql --skip-bundleを実行するとエラーが出る

dockerでrailsの環境構築をしている中でいざ、railsのアプリを作成しようと以下のコマンドを実行
docker-compose run web rails new . --force --database=mysql --skip-bundle

そうすると以下のようなエラーが出る。
ERROR: for mysql Cannot start service mysql: driver failed programming external connectivity on endpoint test-mysql (b2c5bfe3339ba18ad0892ba8fc5a1f427a89b3915035bc12b0c4c1207e016f75): Error starting userland proxy: Bind for 0.0.0.0:3306 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.

ようはそのポートはもう割り振ってしまっていますよって事ですね。
そのためポートを一度削除する必要があります。

まずは占領しているポート番号を特定します。

ポート番号を特定したら以下のコマンドを実行
$ sudo lsof -i:3300 *ここではポート番号3300にしています。

Password:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 94 _mysql 13u IPv6 0x6973239584594d63 0t0 TCP *:mysql (LISTEN)

上の94という番号を今度はkillします。
sudo kill 9447

そうしてもう一度
docker-compose run web rails new . --force --database=mysql --skip-bundle
を実行すれば完了です。

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

Verdaccio+Docker+EC2 その1

今回仕事で任されたタスクをもう一度最初から作っていきます。

Project

同僚がFrontendチームで使うというVerdaccioを何の前知識もなくDockerizeして使えるようにしていく。元々同僚の頭の中では形があったようだが詳細は全く説明されず、最後あたりで説明された。。。

最終的に設定するもの
- docker-compose (Verdaccio, Verdaccio s3 plugin, https-portal)
- Bitbucket pipeline
- git hooks - post-receive

Usage
Verdaccioアクセスはhttps://<サイト>

A. Publish a package
1. チームの誰かがパッケージをパブリッシュする。
2. このパッケージはS3 bucketへ。
3. BitBucket Pipelineを通してプロダクションにデプロイ。

B. Add a new user
1. 新規ユーザーを追加>conf/htpasswdに追加される。
2. BitBucket Pipelineを通してプロダクションにデプロイ。


今回はその1の設定

  • Verdaccio (Dockerfile, config.yaml)
  • EC2 (docker, docker-compose, npm)

Spec and Software

  • Amazon Ubuntu Server 18.04
  • Verdaccio
  • Docker

Path

/home/ubuntu
└── verdaccio
    ├── Dockerfile
    ├── conf
    │   ├── config.yaml
    │   └── htpasswd <- adduserで作られる
    ├── docker-compose.yaml
    ├── package.json <- publishで必要
    ├── plugins
    └── storage
        └── @mypackage <- publishで追加される

verdaccio/conf/config.yaml

storage: /verdaccio/storage
auth:
  htpasswd:
    file: /verdaccio/conf/htpasswd
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
packages:
  '@mypackage/*': <- ポイント
    access: $all
    publish: $authenticated
  '@*/*':
    access: $authenticated
    publish: $authenticated
    proxy: npmjs
  '**':
    proxy: npmjs
logs:
  - {type: stdout, format: pretty, level: http}

verdaccio/package.json

適当に作る。
npm init
名前は上のポイントに合わせる
"name": "@mypackage/verdaccio",

References

Tips for EC2

1) これはちゃんとReferencesのリンクでドキュメントされてます。
sudo chown -R 100:101 verdaccio/

2) 777でないとconf/htpasswdやstorage/@mypackageに書き込めない。他に方法があれば教えてください。
sudo chmod -R 777 verdaccio/conf/
sudo chmod -R 777 verdaccio/storage/

docker内ではこうなってる必要があります。

/ # ls -ltr /verdaccio/
drwxr-xr-x    2 100      101           4096 Jul 27 16:59 plugins
drwxrwxrwx    2 100      101           4096 Jul 27 21:10 conf
drwxrwxrwx    3 100      101           4096 Jul 27 21:11 storage
/ # ls -ltr /verdaccio/conf/
-rwxrwxrwx    1 100      101            372 Jul 27 21:03 config.yaml
-rw-r--r--    1 verdacci nogroup         55 Jul 27 21:10 htpasswd
/ # ls -ltr /verdaccio/storage/@mypackage/
drwxr-xr-x    2 verdacci nogroup       4096 Jul 27 21:28 verdaccio

3) これは見つけるのになかなか時間がかかった。conf/config.yamlのパスをAbsolute Pathにする必要あり。
From
storage: ./storage
TO
storage: /verdaccio/storage

Error Messages

上1&2を設定しないと出るエラー。issues/1136とかで質問されてます。

EACCES: permission denied, open '/verdaccio/conf/htpasswd'
qqq is not allowed to publish package verdaccio : verdaccio

Useful commands

docker-compose up --force-recreate
docker exec -it --user=root verdaccio /bin/sh

Testing

1. docker起動
docker-compose up
expected logging

verdaccio    |  warn --- config file  - /verdaccio/conf/config.yaml
verdaccio    |  warn --- Plugin successfully loaded: verdaccio-htpasswd
verdaccio    |  warn --- http address - http://0.0.0.0:4873/ - verdaccio/4.0.4

2. URLにアクセス

3. Add a user 'qqq'
npm adduser --registry http://<IP>:4873
expected logging
req: 'PUT /-/user/org.couchdb.user:qqq'

4. Login on URL as 'qqq'
expected logging
req: 'POST /-/verdaccio/login'
req: 'GET /-/verdaccio/packages'

5. Publish
npm publish --registry http://<IP>:4873
expected logging
req: 'PUT /@mypackage%2fverdaccio'

6. Refresh URL
expected logging
req: 'GET /-/verdaccio/packages'

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

Dockerベースの機械学習環境を構築できるOSSを作った

概要

自分が所属している研究室のメンバーで、機械学習の実験環境をスムーズに作れるOSSを作り、githubで公開した。

kronos

https://github.com/d-hacks/kronos
こちらにドキュメントなどが書いてあるが、ざっくり説明すると、このcliを入れると、機械学習のプロジェクトディレクトリの中にDockerのファイルを良い感じに作ってくれたり、その中で良い感じにjupyter notebookとかjupyter labとかを開いたり、Dockerのイメージの中でスクリプトを実行したりできる。

何が嬉しいの?

特殊なパッケージをいれたい場合は少しDockerの知識が必要になるが、基本的にはDockerの知識いらずでローカル環境とGPU環境で同じコードを動かすことができる。(内部的にはnvidia-dockerを使っている)

$ kronos init 

ってやると、既存のディレクトリ内に dockerディレクトリができる。

$ kronos build

で、dockerディレクトリ内のファイルを読み込んでイメージをビルドし、

$ kronos run experiment.py

で、イメージ内でスクリプトが実行される。--gpuオプションを使うと、gpuモードになって、gpuをdocker経由でアクセスできるようになる。

まだ足りない点

今後は、より簡単にDockerイメージの中で実験を行えるようにしたいので、opencvだったり、強化学習系の実験に必要なライブラリだったりをもっとも楽にいれられるようにしたい。それこそ、Dockerの知識がなくてもできたら最高に嬉しい。

プルリク大歓迎です

どんどん新しいプルリクを投げてくれると嬉しいです。もっとシームレスなDocker環境の構築ができるツールを作っていきたい。。。

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