20190529のdockerに関する記事は18件です。

一足遅れて Kubernetes を学び始める - 12. リソース制限 -

ストーリー

  1. 一足遅れて Kubernetes を学び始める - 01. 環境選択編 -
  2. 一足遅れて Kubernetes を学び始める - 02. Docker For Mac -
  3. 一足遅れて Kubernetes を学び始める - 03. Raspberry Pi -
  4. 一足遅れて Kubernetes を学び始める - 04. kubectl -
  5. 一足遅れて Kubernetes を学び始める - 05. workloads その1 -
  6. 一足遅れて Kubernetes を学び始める - 06. workloads その2 -
  7. 一足遅れて Kubernetes を学び始める - 07. workloads その3 -
  8. 一足遅れて Kubernetes を学び始める - 08. discovery&LB その1 -
  9. 一足遅れて Kubernetes を学び始める - 09. discovery&LB その2 -
  10. 一足遅れて Kubernetes を学び始める - 10. config&storage その1 -
  11. 一足遅れて Kubernetes を学び始める - 11. config&storage その2 -
  12. 一足遅れて Kubernetes を学び始める - 12. リソース制限 -
  13. 一足遅れて Kubernetes を学び始める - 13. ヘルスチェックとコンテナライフサイクル -

前回

一足遅れて Kubernetes を学び始める - 10. config&storage その2 -では、storageについて学習しました。
今回は、リソース制限について学習します。

※ リソースの種類から、次は「Metadata」だったのですが、kubernetes完全ガイドによると直接説明するのではなく、内容ベースで説明されていましたので、それに準拠します。

リソース制限

kubernetesで管理するコンテナに対して、リソース制限をかけることができます。主にCPUやメモリに対して制限をかけることができますが、Device Pluginsを使うことでGPUにも制限をかけることもできます。

※ CPUの指定方法は、1vCPUを1000millicores(m)とする単位となります。

requestsとlimits

requestは、使用するリソースの下限値です。
limitsは、使用するリソースの上限値です。

requestは、空きノードに指定するリソースがなければスケジューリングされませんが、limitsは、関係なくスケジューリングされます。

とにもかくにも、試してみましょう。

まず、現状確認です。

pi@raspi001:~/tmp $ k get node
NAME       STATUS   ROLES    AGE   VERSION
raspi001   Ready    master   31d   v1.14.1
raspi002   Ready    worker   31d   v1.14.1
raspi003   Ready    worker   30d   v1.14.1
pi@raspi001:~/tmp $ k get nodes -o jsonpath='{.items[?(@.metadata.name!="raspi001")].status.allocatable.memory}'
847048Ki 847048Ki
pi@raspi001:~/tmp $ k get nodes -o jsonpath='{.items[?(@.metadata.name!="raspi001")].status.allocatable.cpu}'
4 4
pi@raspi001:~/tmp $ k get nodes -o jsonpath='{.items[?(@.metadata.name!="raspi001")].status.capacity.memory}'
949448Ki 949448Ki
pi@raspi001:~/tmp $ k get nodes -o jsonpath='{.items[?(@.metadata.name!="raspi001")].status.capacity.cpu}'
4 4

jsonpathの使い方は、こちらにあります。

allocatableがPodに配置できるリソース量で、capacityはNode全体での配置できるリソース量です。
これだけだと、現在使っているリソース量が不明なので個別に調べます。

pi@raspi001:~/tmp $ k describe node raspi002
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests     Limits
  --------           --------     ------
  cpu                200m (5%)    200m (5%)
  memory             150Mi (18%)  150Mi (18%)
  ephemeral-storage  0 (0%)       0 (0%)
...
pi@raspi001:~/tmp $ k describe node raspi003
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests     Limits
  --------           --------     ------
  cpu                400m (10%)   300m (7%)
  memory             320Mi (38%)  420Mi (50%)
  ephemeral-storage  0 (0%)       0 (0%)
...

現状のリソース状況を表にすると下記のとおりです。

node allocatable
(memory/cpu)
capacity
(memory/cpu)
used
(memory/cpu)
remain
(memory/cpu)
raspi002 847,048Ki/4000m 949,448Ki/4000m 150,000Ki/200m 697,048Ki/3800m
raspi003 847,048Ki/4000m 949,448Ki/4000m 320,000Ki/400m 527,048Ki/3600m

では、リソース制限を試してみましょう。

sample-resource.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-resource
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.12
          resources:
            requests:
              memory: "128Mi"
              cpu: "300m"
            limits:
              memory: "256Mi"
              cpu: "600m"

applyするpodで要求するmemoryの下限合計は384Mi(128Mi×3),cpuは900m(300m×3)です。
これだと、podがrunするはずです。

pi@raspi001:~/tmp $ k apply -f sample-resource.yaml
pi@raspi001:~/tmp $ k get pods
NAME                                      READY   STATUS    RESTARTS   AGE
sample-resource-785cd54844-7n89t          1/1     Running   0          108s
sample-resource-785cd54844-9b5f9          1/1     Running   0          108s
sample-resource-785cd54844-whj7x          1/1     Running   0          108s

期待通りですね。
今度はリソース制限になる状態を試してみます。

全WorkerNodeのmemory下限合計は1,224Mi(697,048Ki+527,048Ki)です。
これを超えるように先程のマニフェストを更新します。
replica数を3にしましたが、10にすれば良いですね(1,280Mi)

期待動作として、9個(128Mi*9=1,152Mi)はRunningで、1個(128Mi)はPendingになるはずです。

sample-resource.yamlのreplicaを10に変更したあと↓

pi@raspi001:~/tmp $ k apply -f sample-resource.yaml
pi@raspi001:~/tmp $ k get pods
NAME                                      READY   STATUS    RESTARTS   AGE
sample-resource-785cd54844-7n89t          1/1     Running   0          6m19s
sample-resource-785cd54844-9b5f9          1/1     Running   0          6m19s
sample-resource-785cd54844-dffsd          1/1     Running   0          61s
sample-resource-785cd54844-jmkv6          1/1     Running   0          61s
sample-resource-785cd54844-k9vcb          1/1     Running   0          61s
sample-resource-785cd54844-l4smf          0/1     Pending   0          60s
sample-resource-785cd54844-n4hl7          1/1     Running   0          60s
sample-resource-785cd54844-th4bp          0/1     Pending   0          60s
sample-resource-785cd54844-whj7x          1/1     Running   0          6m19s
sample-resource-785cd54844-xclsk          1/1     Running   0          60s

あれ、2つPendingになっていますね。もしかして、Nodeの空きリソースが中途半端にないからですかね。
確認してみましょう。

pi@raspi001:~/tmp $ k describe node raspi002
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests     Limits
  --------           --------     ------
  cpu                1700m (42%)  3200m (80%)
  memory             790Mi (95%)  1430Mi (172%)
  ephemeral-storage  0 (0%)       0 (0%)
...
pi@raspi001:~/tmp $ k describe node raspi003
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests     Limits
  --------           --------     ------
  cpu                1300m (32%)  2100m (52%)
  memory             704Mi (85%)  1188Mi (143%)
  ephemeral-storage  0 (0%)       0 (0%)
...

raspi002は、847Mi中790Mi使っています。1つのPodを追加するためのリソース(128Mi)はないですね。
raspi003は、847Mi中704Mi使っています。こちらは空いている気がするのですが、なぜでしょうか。

ここで、memoryの704Mi (85%)というところに着目すると、100%だった場合は828Miということになります。
確かに、それだと704Mi+128Mi=832Miでオーバーしています。

では、allocatableで表示されていた847Miとの違いは何でしょうか。
allocatableというのは、全てのnamespaceにあるpodも込みのリソース配置可能量だからです。
defaultだけでなく、kube-systemなど他のnamespaceにあるpodも、もちろんリソースを消費しています。
828Miというのは、defaultで使えるリソース配置可能量ではないでしょうか。(現在のnamespaceはdefault)

ちなみに、Limitsは、100%を超えていますね...。ひぇ〜...。

Cluster Autoscaler

需要に応じてKubernetes Nodeを自動的に追加されていく機能です。
これが動作するタイミングは、PodがPendingになったときに動作します。
つまり、先程の例であったように、requestsの下限によってスケールします。

そのため、requestsが高すぎるために、実際はロードアベレージが低くてもスケールしてしまったり、
requestsが低すぎるために、実際は高負荷でもスケールしなくなったりします。
requestsは、パフォーマンステストをしつつ最適化していきましょう。

LimitRange

さっきの例でもあったように、それぞれに対してrequests,limitを設定しても良いのですが、
もっと便利なものがあります。それがLimitRangeです。
これは、Namespaceに対してCPUやメモリのリソースの最小値や最大値を設定できます。
設定可能な制限項目として、下記があります。

  • default
    • デフォルトのLimits
  • defaultRequest
    • デフォルトのRequests
  • max
    • 最大リソース
  • min
    • 最小リソース
  • maxLimitRequestRatio
    • Limits/Requestsの割合

また、制限する対象は、Container,Pod,PersistentVolumeClaimがあります。
実運用する際は、きちんと定義しておきましょう。(プロバイダーによってはデフォルトで設定されているものもあるそうです)

ResourceQuota

ResourceQuotaを使うことで、Namespaceごとに「作成可能なリソース数の制限」と「リソース使用量の制限」ができます。
「作成可能なリソース数の制限」を試そうと思います。

sample-resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: sample-resourcequota
  namespace: default
spec:
  hard:
    # 作成可能なリソースの数
    count/pods: 5
pi@raspi001:~/tmp $ k delete -f sample-resource.yaml
pi@raspi001:~/tmp $ k apply -f sample-resourcequota.yaml
pi@raspi001:~/tmp $ k apply -f sample-resource.yaml
pi@raspi001:~/tmp $ k get pods
NAME                                      READY   STATUS    RESTARTS   AGE
sample-resource-785cd54844-dll8t          1/1     Running   0          38s
sample-resource-785cd54844-ljr7q          1/1     Running   0          39s
sample-resource-785cd54844-r6txh          1/1     Running   0          38s
sample-resource-785cd54844-sb6sq          1/1     Running   0          38s
sample-resource-785cd54844-3ffeg          1/1     Running   0          38s

こうすると、podsが5個までしか作成できないので、sample-resource.yamlを適用しても5個までしか作成されません。
replicaのような場合は、特に警告がなく単純に作られませんでした。
configmapを5個までに制限して、1つずつconfigmapをapplyすると、警告がでるそうです。

HorizontalPodAutoscaler(HPA)

HPAは、Deployment,ReplicaSetで管理するPodのCPU負荷などに応じて自動的にスケールするリソースです。
30秒に1回の頻度でスケールするかチェックしています。

必要なレプリカ数は、下記の数式で表します。

  • 必要なレプリカ数 = ceil(sum(Podの現在のCPU使用率)/targetAverageUtilization)

KubernetesのPodとNodeのAuto Scalingについてで、

auto scalingはtarget valueに近づくようにpod数が調整されるということ。

という文がわかりやすかったです。つまり、targetAverageUtilizationが50なら、全体のCPU使用率が50%になるよう調整されます。
今回、試そうと考えたのですが、metrics-serverをinstallしていないため、動作確認できませんでした。
また今度installして試してみようと思います。

VerticalPodAutoscaler(VPA)

VPAは、コンテナに割り当てるCPUやメモリのリソース割当をスケールさせるリソースです。
これは、HPAのスケールアウトではなく、Podのスケールアップを行うものです。

お片付け

pi@raspi001:~/tmp $ k delete -f sample-resource.yaml -f sample-resourcequota.yaml

最後に

今回は、RequestsやLimitsを操作してリソース制限をしてみました。
どれがいくらリソースを消費しているのか確認する術を学び、
ついでにjsonpathの使い方も知りました。
次回は、こちらです。

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

Rspecで突然謎のエラーが

circleCIで通常通り動いていたテストコードが突然動かなくなりましたが解決したのでその方法を書いていきます。

開発環境

Ruby 2.6.2
Rails 5.2.3
Docker 18.09.2
docker-compose 1.23.2

今回発生したエラー

Selenium::WebDriver::Error::UnknownError:
    unknown error: session deleted because of page crash
    from unknown error: cannot determine loading status
    from tab crashed

原因

エラーを調べたところ日本語での記事が少なく詳しくはわからなかったのですが、メモリ不足によってクラッシュしてしまうとのこと。
ブラウザのサイズを小さくすれば解決するとの記事を見て試してみたのですが、僕の場合小さくしても解決しませんでした。

解決方法

rails_helperのchromeOptionsのところに--no-sandbox--disable-dev-shm-usageというargumentsを追加してください。--disable-dev-shm-usageと書くことでChromeは/tmpディレクトリを代わりに使用するようになるみたいです。メモリの代わりにディスクが使用されるので、実行が遅くなる場合があるみたいですがそんなに変わってない気がします。

spec/rails_helper.rb
Capybara.register_driver :selenium_remote do |app|
  driver = Capybara::Selenium::Driver.new(
      app,
      browser: :remote,
        desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(
            chromeOptions: {
                args: [
                    'window-size=500,500', #念の為サイズも小さく
                    'headless',
                    '--no-sandbox', # crush回避
                    '--disable-dev-shm-usage' # crush回避
                ]
            }
        ),
        url: 'http://chrome:4444/wd/hub',
    )
end

これで解決すると思います。

もし間違いがあれば訂正お願いいたします。

参考サイト

https://qiita.com/jb-vasseur/items/d3aa33e08ebba3b9231e
https://stackoverflow.com/questions/53902507/unknown-error-session-deleted-because-of-page-crash-from-unknown-error-cannot

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

Ruby/Ruby on rails/MysqlをDockerで環境構築

DockerでRuby/Ruby on rails/mysqlの環境構築からデプロイまでできたのでメモしておきます。

(1)Dockerfile作成

Dockerfile

FROM ruby:2.5.3


RUN apt-get update -qq && \
    apt-get install -y build-essential \ 
                       libpq-dev \        
                       nodejs           

RUN mkdir /app_name 

ENV APP_ROOT /app_name 
WORKDIR $APP_ROOT

ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock


RUN bundle install
ADD . $APP_ROOT

(2)docker-compose.yml作成

docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    ports:
      - "3306:3306"

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app_name
    ports:
      - "3000:3000"
    links:
      - db

(3)Gemfile作成

Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.2'

Gemfile.lockも作成
$ touch Gemfile.lock

(4)新しいアプリを作成

$ docker-compose run web rails new アプリ名 . --force --database=mysql --skip-bundle

databese.ymlを編集

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password 
  host: db 

Gemfileをbundle install

$ docker-compose run web bundle install

(5)コンテナをビルドと起動

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

$ docker-compose up # コンテナの一斉起動

※bundle installの後にbuildする

(6)DB作成

$ docker-compose run web rails db:create

DBを作らないとエラーが出る

DBを作成後localhost:3000で初期画面が表示される!

()Herokuでデプロイ

herokuの登録,heroku cliはインストール済みとする

Herokuにアプリ作成

$ heroku create

データベースをMySQLに変更

$ heroku addons:add cleardb

ClearDBアドオンとは,ClearDBというデータベースサービスが提供している,MySQLを使うためのもの。

$ heroku config | grep CLEARDB_DATABASE_URL
mysql:// 〜 reconnect=trueがデータベース情報

mysqlの部分をmysql2に変更

環境変数を変更

$ heroku config:set DATABASE_URL=mysql2:// 〜 reconnect=true     //先ほどのデータベース情報全部
$ git add .
$ git commit -m "update for upload to heroku"

アプリをデプロイ

$ git push heroku master

マイグレーションファイル作成

$ heroku run rake db:migrate

参考

丁寧すぎるDocker-composeによるrails + MySQL on Dockerの環境構築

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

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

最近Dockerの履修を始めたので自分用めも。

確認系

# dockerの色々を確認
$ docker info

# 動いているコンテナを見る
$ docker ps

# 動いていないコンテナも見る
$ docker ps -a

# イメージの確認
$ docker images

コンテナ起動関係

CONTAINER IDは特定ができる所まで入力すれば省略が可能。

# コンテナを起動
$ docker start [CONTAINER ID]

# コンテナを終了
$ docker stop [CONTAINER ID]

# コンテナに入る
$ docker attach [CONTAINER ID]

# コンテナを終了
$ exit

# コンテナを抜ける
$ Ctrl + p + q

削除系

イメージが使っているコンテナが存在する場合エラーを投げてくれるので、不要なイメージを削除する場合は不要なコンテナを先に削除する。

# コンテナの削除。複数指定可能
$ docker rm [CONTAINER ID] [CONTAINER ID] ......

# コンテナを全て削除。注意
$ docker rm `docker ps -a -q`

# イメージの削除
$ docker rmi [IMAGE ID]

その他

# イメージのリネーム
$ docker tag [SRC REPOSITORY]:[SRC TAG] [DST REPOSITORY]:[DST TAG]
$ docker rmi [SRC IMAGE ID]

# コンテナをファイル出力
$ docker export [CONTAINER ID] > [DST].tar

# ファイルからコンテナを作成
$ cat [SRC].tar | docker import - [REPOSITORY]:[TAG]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker runコマンドでhoge && tail -f hoge.logでゾンビコンテナになる

概要

dockerコンテナを永続化する方法としてRUNコマンドにhoge & tail -f hoge.logのようにしているならば要注意です!
場合によってはゾンビコンテナになります!
なぜそうなるのかというと、メインプロセス(フォアグラウンドプロセスでも)が異常終了してもtailコマンドが正常である限り、そのまま稼働し続けるからです!
restart policyが定義されていても期待した動作にならないでしょう!

検証方法

例として、RUNコマンドでhoge && tail -f hoge.logが定義されているとする。
hogeプロセスをkillしてみてください!
tail -f hoge.log だけを実行するゾンビコンテナの出来上がりです!

対策法

監視システムが導入されているならば、メインプロセスの状態を監視して異常時に自動起動するような仕組みを導入する。
他にいい方法があればご教授ください!

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

docker runコマンドでhoge && tail -f hoge.logでゾンビになる

概要

dockerコンテナを永続化する方法としてRUNコマンドにhoge & tail -f hoge.logのようにしているならば要注意です!
場合によってはゾンビコンテナになります!
なぜそうなるのかというと、メインプロセスが異常終了してもtailコマンドが正常である限り、そのまま稼働し続けるからです!
restart policyが定義されていても期待した動作にならないでしょう!

検証方法

例として、RUNコマンドでhoge && tail -f hoge.logが定義されているとする。
hogeプロセスをkillしてみてください!
tail -f hoge.log だけを実行するゾンビコンテナの出来上がりです!

対策法

監視システムが導入されているならば、メインプロセスの状態を監視して異常時に自動起動するような仕組みを導入する。
他にいい方法があればご教授ください!

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

Dockerfileを楽に作りたい

この記事には修正版があります.そちらをご覧ください. -> https://qiita.com/RyodoTanaka/items/c7e4889a1b9383291799

2019.05.29時点で下記手順でうまく行かない事を確認しました...orz -> 修正しました(2019.05.30)

修正版を作りました.
https://qiita.com/RyodoTanaka/items/c7e4889a1b9383291799


表題のとおりです.
Dockerfileを楽に作りたいなぁと思った時,どうやりますか?
私は下のような手順で出来るといいなと思ってます.

  1. Docker image の実行
  2. 環境構築
  3. imageからDockerfileを作成

1. Docker image の実行

例えば,Ubuntu 16.04をベースにしたいなと思ったとき,まずはimageを引っ張ってきますよね.

$ docker pull <image repository name> 

でもってPullが完了したら,そいつを実行します.

$ docker run -it <image name>

2. 環境構築

実行してるcontainer内で色々環境構築します.
具体的に何をするかは皆様お好きに!
環境構築が終わったらexitコマンドとか使って終了します.

3. containerからimageを作成する

まずはcontainer 情報を下記コマンドで確認します.
ここからDockerfileを作りたいcontainer IDか名前を取得します.

$ docker ps -a

そしたら,下記コマンドで希望のcontainerを任意の名前のimageにします.

$ docker container commit <container ID> <image name>

一応作成し終わったら,下記コマンドでimageがちゃんと作られてるか確認します.

$ docker images

4. imageからDockerfileを作成

はい.やっと本記事のミソですね.
適当にぐぐったところ,海外の方が神bashをアップしてくださってました.
やっぱりStack Overflow なしでは生きていけません.
https://stackoverflow.com/a/50926503

$ docker history --no-trunc <image name>  | tac | tr -s ' ' | cut -d " " -f 5- | sed 's,^/bin/sh -c #(nop) ,,g' | sed 's,^/bin/sh -c,RUN,g' | sed 's, && ,\n  & ,g' | sed 's,\s*[0-9]*[\.]*[0-9]*[kMG]*B\s*$,,g' | head -n -1

ただ,こいつ長いですよね.
なので,dfimageというコマンドを作りました.
https://github.com/RyodoTanaka/.bash_extend/blob/master/dfimage.bash
こいつを.bashrcで読み込んでやれば,

$ dfimage <image name>

とするだけで,Dockerfileを標準出力に出力してくれます.
なのでUNIX系使いの方であれば

$ dfimage <image name> > Dockerfile

とすれば自動でDockerfileが出来上がります!

まとめ

というわけで,dfimageコマンドを作って簡単にDockerfileが作成できるようにしました.
これでDocker Hubにイメージをアップしまくれますね!!!

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

Dockerfileを楽に作りたい(imageから自動生成したい)

この記事には修正版があります.そちらをご覧ください. -> https://qiita.com/RyodoTanaka/items/c7e4889a1b9383291799

2019.05.29時点で下記手順でうまく行かない事を確認しました...orz -> 修正しました(2019.05.30)

修正版を作りました.
https://qiita.com/RyodoTanaka/items/c7e4889a1b9383291799


表題のとおりです.
Dockerfileを楽に作りたいなぁと思った時,どうやりますか?
私は下のような手順で出来るといいなと思ってます.

  1. Docker image の実行
  2. 環境構築
  3. imageからDockerfileを作成

1. Docker image の実行

例えば,Ubuntu 16.04をベースにしたいなと思ったとき,まずはimageを引っ張ってきますよね.

$ docker pull <image repository name> 

でもってPullが完了したら,そいつを実行します.

$ docker run -it <image name>

2. 環境構築

実行してるcontainer内で色々環境構築します.
具体的に何をするかは皆様お好きに!
環境構築が終わったらexitコマンドとか使って終了します.

3. containerからimageを作成する

まずはcontainer 情報を下記コマンドで確認します.
ここからDockerfileを作りたいcontainer IDか名前を取得します.

$ docker ps -a

そしたら,下記コマンドで希望のcontainerを任意の名前のimageにします.

$ docker container commit <container ID> <image name>

一応作成し終わったら,下記コマンドでimageがちゃんと作られてるか確認します.

$ docker images

4. imageからDockerfileを作成

はい.やっと本記事のミソですね.
適当にぐぐったところ,海外の方が神bashをアップしてくださってました.
やっぱりStack Overflow なしでは生きていけません.
https://stackoverflow.com/a/50926503

$ docker history --no-trunc <image name>  | tac | tr -s ' ' | cut -d " " -f 5- | sed 's,^/bin/sh -c #(nop) ,,g' | sed 's,^/bin/sh -c,RUN,g' | sed 's, && ,\n  & ,g' | sed 's,\s*[0-9]*[\.]*[0-9]*[kMG]*B\s*$,,g' | head -n -1

ただ,こいつ長いですよね.
なので,dfimageというコマンドを作りました.
https://github.com/RyodoTanaka/.bash_extend/blob/master/dfimage.bash
こいつを.bashrcで読み込んでやれば,

$ dfimage <image name>

とするだけで,Dockerfileを標準出力に出力してくれます.
なのでUNIX系使いの方であれば

$ dfimage <image name> > Dockerfile

とすれば自動でDockerfileが出来上がります!

まとめ

というわけで,dfimageコマンドを作って簡単にDockerfileが作成できるようにしました.
これでDocker Hubにイメージをアップしまくれますね!!!

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

Docker on Storybook@Vueを最小構成で動かす

何時もの備忘録として

  • docker-compose runの仕様にはまった

まずはチュートリアル通りに動かす

こちらを参照に進める

docker-compose.ymlの準備

version: '3'
services:
  node:
    image: node:12.3.1-alpine
    volumes: 
      - ./:/app
    working_dir: /app
    ports:
      - 9001:9001

モジュールをインストール

docker-compose run node npm init
docker-compose run node npm install @storybook/vue --save-dev
docker-compose run node npm install vue --save
docker-compose run node npm install vue-loader vue-template-compiler @babel/core babel-loader babel-preset-vue --save-dev

packeage.jsonの編集

以下を追加

packeage.json
{
  "scripts": {
    "storybook": "start-storybook --ci -p 9001 -c .storybook",
  }
}

設定ファイルを作成

.storybook/config.jsを作成 .storybookディレクトリに注意

storybook/config.js
import { configure } from '@storybook/vue';

function loadStories() {
  require('../stories/index.js');
}

configure(loadStories, module);

./stories/index.jsを作成

index.js
import Vue from 'vue';
import { storiesOf } from '@storybook/vue';
import MyButton from '../components/Button';

storiesOf('Button', module)
  .add('with text', () => '<my-button>with text</my-button>')
  .add('with emoji', () => '<my-button>? ? ? ?</my-button>')
  .add('as a component', () => ({
    components: { MyButton },
    template: '<my-button :rounded="true">rounded</my-button>'
  }));

./components/Button.vueを作成

Button.vue
//何でもいいので作る

<template>
  <button @click="hello">hello</button>
</template>

<script>
export default {
  methods: {
    hello: e => {
       alert('hello');
    }
  }
}
</script>

そして

docker-compose run run node run storybook

でブラウザが開かない。。。

docker-compose runの仕様でそのままだとportsのマッピングが効かない。知らなかった。。。

気を取り直して

docker-compose run --service-ports node npm run storybook

localhost:9001でStorybookが確認できる

スクリーンショット 2019-05-29 16.32.46.png

参考

チュートリアル
Issue

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

Spring Boot� / Thymeleafの基礎を学ぶ【初心者向け】

はじめに

この記事は社内でSpring Boot(実質的にはSpring?)の勉強会を行うにあたり作成した資料となります。
1時間程度で済む簡単なものになっています。
「Spring Bootってこんな感じなんだ」ということが少しでも伝われば幸いです。
なお、私自身Spring並びにSpring Boot初心者なため、記事に誤っている点があるかもしれません。
その際はご指摘いただけますと幸いです。

環境

  • Mac
  • Spring 2.0.2
  • Dokcer for Mac
  • Gradle 5.2.1
  • VSCode

※Eclipseでええやん!って人はDockerじゃなくても○。
※Gradleについては以下の記事が分かり易かったです。
→  多分わかりやすいGradle入門
  Gradle入門

Springについて

強み

  • 変更に強い
    • DI(Dependency Injection)という仕組みが導入されている。
      • それぞれが独立しているため依存度が低く、変更に強い。
  • 拡張性が高い
    • 基本的な機能の大部分が インターフェース として提供されている。
    • 必要な部分は簡単に追加できる。
  • 保守性が高い
    • AOP(アスペクト指向プログラミング) を用いることができる。
      • 共通のプログラムを再利用することでコーディング量減・修正も簡単
  • テストが簡単
    • Spring MVC Test という専用のテストプログラムで結合テストが簡単にできる。
  • 大規模データベース NoSQL に対応

弱み

  • フレームワークの規模が大きく、全体を把握するのが難しい。
  • DIコンテナの正しい使い方が難しい
  • 日本語のドキュメントが乏しい

じゃあSpring Bootって何?

WEBアプリケーションに特化した「Spring MVC」というフレームワークの完成形として、Spring MVCやその他のSpring Frameworkのライブラリ類をいい感じに組み合わせたWebアプリケーション環境を簡単に構築するライブラリです。

【参考: [Java] Spring BootでHello World!(入門編)

その特徴を簡単にまとめると、

1.アノテーションを記述するだけで実装できる機能が多数あり、コード量を削減できる
2.Webコンテナをjarに内蔵することで、jar単体でWebアプリケーションが実行できる
3.今までのSpringフレームワークでは必須だった、XML設定ファイルが不要になった
4.Spring Initializrというプロジェクト雛形生成サービスがあり、一から開発する必要がない

などなど様々な高速システム開発のための機能が提供されています。

[Java] Spring Bootで簡単・高速にWebAPI開発

下準備

  • Docker for Macをインストールし、 docker コマンドが打てることを確認する。
  • 以下のコマンドを実行する。
$ git clone https://github.com/miwa0519/spring-boot.git
$ cd spring-boot/spring_boot_docker/
  • 以下のコマンドを実行。
    • Tomcatが8080ポートで動く。
    • 3000番ポートは人気者だから別ポートがいい、という場合は docker-compose.yml 内の3000部分を別の番号に変えるといい。
    • Springが上手く動いていればコンソールに Spring>>> みたいな例のAAが出る。出ると少しテンションが上がる。
$ docker build -t spring-docker ./
$ docker run -p 3000:8080 spring-docker

今回のサンプルだと、ソースコードを編集する度に上記コマンドを実行する必要があります。
今後改善予定です。面倒臭くてすみません:bow_tone1:

  • ※こちらは必要な人のみ
    • こちらの記事 でVSCode向けのプラグインを取り纏めてくださっています。 import とか手入力してられるかよ!という人にはオススメです。

とりあえずHello Worldしてみる

src/main/java/com/example/demo 直下に HelloController.java を作成します。
HelloController.java 内に以下のソースを記述します。

src/main/java/com/example/demo/HelloController.java
package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
  @RequestMapping("/hello")
  public String hello() {
    return "Hello World!";
  }
}

http://localhost:3000/hello
にアクセスすると Hello World! と表示されていると思います。

スクリーンショット 2019-05-29 12.52.38.png

アノテーションが二つ出てきました。これらが何をしているかを簡単に説明します。

  1. @RestController :RestControllerアノテーションをつけると、このコントローラーが Webアプリケーション のリクエストを受け付ける Restコントローラー になる。
  2. @RequestMapping :RequestMappingアノテーションをつけると、ルーティングを行なってくれる。今回でいうと、 http://localhost:3000/hello にアクセスすると Hello メソッドを実行する、という紐付けが行われる。

これらが使えるように、それぞれのクラスをインポートしてます。インポート出来ていないとコンパイルエラーになるので気をつけてください。

もう少しWebアプリらしく Hello World! したいので、今度はテンプレートを作ってみたいと思います。

Viewの部分を実装する

Spring Bootでは1.2以降はJSPが非推奨とされています。
なので今回は Thymeleaf というテンプレートエンジンを使います。
Spring Bootでは Thymeleafを使うのが無難らしいです。

Thymeleafを使えるように設定する

設定をしないとThymeleafは使えません。

build.gradle を以下のように書き換えてください。

build.gradle
// 中略

dependencies {
+   compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

実際にHTMLを書いてみる

Thymeleafの設定ができたので、実際にHTMLを書いてViewを実装していきます。
src/resources 直下に templates ディレクトリを用意し、 hello.html ファイルを作成します。

src/main/resources/templates/hello.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Thymeleaf</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <p th:text="'Hello Wonderful World!'" />
  </body>
</html>

th:textThymeleaf の属性。Thymeleafの記述については以下が分かりやすかったです。
[Java] Spring BootでThymeleafを使ってみよう!(応用編)

HelloControllerを修正する

テンプレートを用意したので、今度はコントローラーがそのテンプレートを呼び出してくれるように修正します。

HelloController.java
package com.example.demo;

  import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
+ import org.springframework.stereotype.Controller;
+ import org.springframework.web.bind.annotation.RequestMethod;

- @RestController
+ @Controller
  public class HelloController {
    @RequestMapping("/hello")
    public String hello() {
-     return "Hello World!"
+     return "hello";
    }
  }

@RestController@Controller に変更しました。
これにより、WebAPIとして機能していた HelloControllerMVCC として振る舞うようになります。
それにより、 return の部分に記載した helloViewResolver がView名として認識し、実際のファイル名に変換し、クライアントに返却します。

最初のコマンドを再度実行した後に
http://localhost:3000/hello
をリロードします。テンプレートが呼び出されて、表示される文言が変わっていることが確認できると思います。

スクリーンショット 2019-05-29 12.56.17.png

簡単な計算アプリを作ってみる

MVCのVとCについてはここまでで学ぶことが出来ました。
最後にModelについての説明を加えながら、与えた数字を元に足し算を行ってくれる簡単なアプリを作成したいと思います。

Model作ってみる

まず、フォームの値を受け取って計算するためのモデルを作成します。
Controllerを作成したディレクトリの中に model ディレクトリを作成し、その中に Form.java を作成します。

src/main/java/com/example/demo/model/Form.java
package com.example.demo.model;

public class Form {

  private int num1 = 0;
  private int num2 = 0;
  private int total = 0;

  public int getNum1(){
    return num1;
  }

  public void setNum1(int num){
    this.num1 = num;
  }

  public int getNum2(){
    return num2;
  }

  public void setNum2(int num){
    this.num2 = num;
  }

  public int getTotal(){
    return total;
  }

  public void setTotal(int total){
    this.total = total;
  }
  public void sumTotal(){
    total = this.num1 + this.num2;
    setTotal(total);    
  }
}

入力値を保持する num1num2 と合計値を保持する total フィールドを作成し、それぞれに gettersetter を定義します。
また、 num1num2 の合計を算出する sumTotal メソッドを定義しておきます。

入力フォームを表示する

modelを定義したので、次は入力フォームを表示してみます。
まず、入力フォームを表示するためのコントローラーを定義します。

src/main/java/com/example/demo/CalculateController.java
package com.example.demo;
import com.example.demo.model.Form;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

@Controller
public class CalculateController {
  @RequestMapping("/calculate")
  public String form(Model model){
    model.addAttribute("form", new Form());
    return "index";
  }
}

今までの Controller と違うところは、メソッドに Model 型のオブジェクトを引数に取っているところです。
この Model に値をセットすることでHTMLに値を渡す事が出来ます。(Springが用意してくれているクラス)
model.addAttribute("form", new Form()) の部分で、 model に対し、Formインスタンスを渡しています。

model.addAttribute("変数名", オブジェクト)

※ちなみに、第2引数に Form form と記述しても同じ意味になります。(裏で
addAttribute と同じことが実行されるイメージ)

【参考:【Spring Boot】ModelクラスとModel And Viewクラス

form メソッドでは index というテンプレートを最後に返しています。
今度は index テンプレートを作成し、入力画面を作成します。

入力画面を作る

src/main/resources/templates/index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Index</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <h1>Form</h1>
    <form action="#" th:action="@{/result}" th:object="${form}" method="post">
      <p>first number: <input type="number" th:field="*{num1}" /></p>
      <p>Second number: <input type="number" th:field="*{num2}" /></p>
      <p><input type="submit" value="calculate" /></p>
    </form>
  </body>
</html>

最初に作った hello.html と異なるところは、 th:actionth:objectth:field という属性が出てきている点です。
なんとなく見た目で伝わるかと思いますが、簡単に使い方だけご紹介します。

th:action   th:object th:field="*{フィールド名}"
フォームのアクションを指定する ${}で指定したオブジェクトにフォームで入力した値が入る。 th:objectで指定しているオブジェクトのフィールドに対して入力された値を入れる。

【参考: [Spring Boot でフォームの値を取得して操作] 】(https://qiita.com/NariseT/items/172ca093364aa9391989)

各テキストエリアに入力された値は、先ほどコントローラーで Model オブジェクトに追加した Form インスタンスの各フィールドに値がセットされます。

http://localhost:3000/calculate
にアクセスすると入力フォームが表示されるはずです。

スクリーンショット 2019-05-29 13.54.42.png

Controllerを修正する

今度はフォームで入力した値を受け取り、計算を行い、その結果を画面に表示できるようにします。
まずはコントローラーに新しいメソッドを追加します。

src/main/java/com/example/demo/CalculateController.java
package com.example.demo;
import com.example.demo.model.Form;

// 中略
  import org.springframework.ui.Model;
+ import org.springframework.web.bind.annotation.RequestMethod;
+ import org.springframework.web.bind.annotation.ModelAttribute;

  @Controller
  public class CalculateController {
    @RequestMapping("/calculate")
    public String form(Model model){
      model.addAttribute("form", new Form());
      return "index";
  }

+   @RequestMapping(value="/result", method = RequestMethod.POST)
+   public String result(@ModelAttribute Form form, Model model){
+     form.sumTotal();
+     model.addAttribute("form", form);
+     return "result";
+   }
  }

@RequsetMapping は今回パラメータを受け取るので、HTTPメソッドを指定します。
method = RequestMethod.post と記載することでこれはPOSTだよ!と指定できます。
また今回はメソッドの引数に @ModelAttribute というアノテーションがついています。このアノテーションをつけると input の値を受け取ることが出来ます。

form の各フィールドには入力フォームで入力された値がセットされている状態なので、 Form クラスで定義した sumTotal メソッドを呼び出し、 formtotal フィールドに合計値を保持させます。

その結果を result テンプレートに表示させたいので、今度は result テンプレートを作成します。

計算結果を画面に表示する

templates ディレクトリ直下に以下のファイルを作成してください。

src/main/resources/templates/result.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Result</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <h1>Result</h1>
    <p th:text="'Answer: ' + ${form.getTotal()}" />
    <a href="/calculate">Calculate Another number</a>
  </body>
</html>

${} で式展開を行なってくれるので、getterを使っての合計値を取得し、表示します。

計算実行結果は以下です。

スクリーンショット 2019-05-29 13.59.03.png
スクリーンショット 2019-05-29 13.28.57.png

最後に

私自身がSpring Bootについて初歩的な部分を学んで感じたのは以下の三点です。

  • 面倒な設定が少なく、すぐに開発に取りかかれた。(Dockerで動かすのが大変だったくらい)
  • ソースコードが割と直感的に書ける
  • 自分の求めているドキュメントに辿り着くまでの時間が壮大(自分の調べ方が下手なだけかも)

とはいえ私自身、初歩的な部分しかまだ分からない状況なので、今後も少しずつ学んでいけたらと思っております。
この記事がSpring Boot、Spring初心者の何かの皆さんの役に立てば幸いです。

参考

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

オフラインUbuntuで機械学習やKaggle用環境構築(Docker)

オフライン環境で辛い中、頑張ってUbuntuの環境構築をしましょうシリーズの続き。今回はdockerで機械学習用の基礎環境を構築する。

前回はこちら(オフライン環境でapt install:Dockerをインストール)
https://qiita.com/tetrar124/items/40fd9b1ff5f0b015a6da

各ステップ
1. オンライン環境でビルドして必要なパッケージを追加したkaggleイメージを作成
2. イメージをアーカイブ化後、オフライン環境へコピー
3. docker-compseで必要な設定を追加して完成

※注意点
kaggle-pythonコンテナは現時点でGPU非対応。

https://github.com/Kaggle/docker-python
GPUを使う際はtensorflowコンテナなど、別なコンテナを選ぶ必要がある。

1. オンライン環境でkaggleコンテナに必要なパッケージを追加

下記のDockerfileを作成する。

Dockerfile

# kaggleのpythonコンテナを使用
FROM gcr.io/kaggle-images/python:latest
# パッケージの追加
RUN pip install -U pip && \
    pip install fastprogress japanize-matplotlib

今回はオフライン環境なのでlatestに指定したが、オンラインの場合はバージョンを指定するのが好ましい。
バージョンは下記サイトで調査可能(2019/5/29現在はv56が最新)。

Google container Registryのkaggle pythonレポジトリ
https://console.cloud.google.com/gcr/images/kaggle-images/GLOBAL/python

$sudo docker load < pythonLocal.tar
$docker-compose up --build

Dockerfileを用いてビルドし、local/kaggleイメージを作成する。Dockerfileのあるフォルダで下記を実行。

$ sudo docker build  ./ -t local/kaggle

2. 作成したイメージをアーカイブ化後、オフライン環境へコピー

$ sudo docker save local/kaggle > kaggle.tar

kaggle.tarファイル(15G!)をオフライン環境へ頑張ってコピーする。
(NIC二枚刺しにしてオフライン装置へ接続、scpが楽)

オフラインUbuntuのコピーしたファイルのあるフォルダで下記を実行し、イメージをロードする。

$ sudo docker load < kaggle.tar

3. docker-compseで必要な設定を追加して完成

Dockerfile

FROM local/kaggle

docker-compose.yaml

version: "2"
services:
  jupyter:
    build: .
    volumes:
      - ~/tmp:/tmp/working
    working_dir: /tmp/working
    ports:
      - 1234:8888
    command: jupyter notebook --ip=0.0.0.0 --allow-root --no-browser --NotebookApp.token=''

※ Ubuntuのdocker-composeはvesion: "2" にしないとエラーが出る

  • portsの項目は、コンテナのポート8888をlocalhostの1234に転送する設定。
  • volumesの - ~/tmp:/tmp/working は、Dockerのホストマシン(今回はオフライン環境Ubuntu)の~/tmpフォルダをコンテナの/tmp/workingとして共有する設定。今回は~/tmpファイルのセーブ先、必要なファイルを入れる共有フォルダとして使用する。
  • ローカルネットを想定しているため--NotebookApp.token=''のオプションで認証を回避した。

下記コマンドでコンテナが起動する。

$ docker-compose up build

ブラウザに localhost:1234と入れる事でJupyter notebookにアクセスできる。

ネットワーク内の場合は、ブラウザに
dockerを動かすホストマシンIPのアドレス:1234
と入れる事でリモートアクセスできる。

※事前にdockerを動かすマシンを下記コマンドでポート開放すること。
(fromオプションでローカルのみにした方が安全)

$ sudo ufw allow from 192.168.0.0/24 to any port 1234

4. GPU用の設定インストール

参考

https://amalog.hateblo.jp/entry/data-analysis-docker

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

Docker Scratch

scratchのDocker

前の記事では、「FROM scratch」からDockerfileを書き、それに「alpine-minirootfs」を追加して始めました。
では、「FROM scratch」の状態でどんな感じなんでしょう。

まず、busyboxを用意します。以下の内容としました。

6c82cf6b59b1:/tmp$ tar tvf busybox-1.30.1.tar.gz
drwxr-sr-x build/build       0 2019-05-29 00:52 bin/
-rwxr-xr-x build/build  833104 2019-05-29 00:37 bin/busybox
drwxr-sr-x build/build       0 2019-05-29 00:44 lib/
-rwxr-xr-x build/build  584304 2019-05-29 00:44 lib/ld-musl-x86_64.so.1

これを用いて、Dockerfileを作ります。

FROM scratch
ADD busybox-1.30.1.tar.gz /
CMD ["/bin/busybox","sh"]

では、動かしてsys/proc以外をリストしてみましょう。

/ #  /bin/busybox ls -l bin dev etc lib
bin:
total 816
-rwxr-xr-x    1 1000     1000        833104 May 29 00:37 busybox

dev:
total 0
crw--w----    1 0        5         136,   0 May 29 01:04 console
lrwxrwxrwx    1 0        0               11 May 29 01:00 core -> /proc/kcore
lrwxrwxrwx    1 0        0               13 May 29 01:00 fd -> /proc/self/fd
crw-rw-rw-    1 0        0           1,   7 May 29 01:00 full
drwxrwxrwt    2 0        0               40 May 29 01:00 mqueue
crw-rw-rw-    1 0        0           1,   3 May 29 01:00 null
lrwxrwxrwx    1 0        0                8 May 29 01:00 ptmx -> pts/ptmx
drwxr-xr-x    2 0        0                0 May 29 01:00 pts
crw-rw-rw-    1 0        0           1,   8 May 29 01:00 random
drwxrwxrwt    2 0        0               40 May 29 01:00 shm
lrwxrwxrwx    1 0        0               15 May 29 01:00 stderr -> /proc/self/fd/2
lrwxrwxrwx    1 0        0               15 May 29 01:00 stdin -> /proc/self/fd/0
lrwxrwxrwx    1 0        0               15 May 29 01:00 stdout -> /proc/self/fd/1
crw-rw-rw-    1 0        0           5,   0 May 29 01:00 tty
crw-rw-rw-    1 0        0           1,   9 May 29 01:00 urandom
crw-rw-rw-    1 0        0           1,   5 May 29 01:00 zero

etc:
total 12
-rw-r--r--    1 0        0               13 May 29 01:00 hostname
-rw-r--r--    1 0        0              174 May 29 01:00 hosts
lrwxrwxrwx    1 0        0               12 May 29 01:00 mtab -> /proc/mounts
-rw-r--r--    1 0        0              101 May 29 01:00 resolv.conf

lib:
total 572
-rwxr-xr-x    1 1000     1000        584304 May 29 00:44 ld-musl-x86_64.so.1
/ #

最低限のデバイスのみですね。
busybox:muslのmusl/Dockerfileも見てみます。

FROM scratch
ADD busybox.tar.xz /
CMD ["sh"]

上に書いたのと同じようなことをやっていますね。

変更履歴

(2019/5/30) shのリンクを削除し、busyboxを使用する変更

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

docker unity

dockerでunityを動かしたく調べ始める。

UnityEditorのバージョン管理をしたい
https://qiita.com/Sashimimochi/items/06c136487b8150e35ed0

最近流行りのDockerを使ってUnityを動かせないかと思いました。結論から言うとおすすめしません。それでも、供養の意味も込めて検討記録ということで長くはなりますが、それでもいいよという心優しい方はお付き合いください。

nenadg/docker-unity3d
https://github.com/nenadg/docker-unity3d

条件

Unityをhostに導入するのは嫌。
dockerの外でcompileするのは嫌。
dockerの中でcompileするのはOK.

gableroux/unity3d
https://hub.docker.com/r/gableroux/unity3d/

unity3d
https://gitlab.com/gableroux/unity3d

$ docker run -it --rm   -v "$(pwd):/root/project"   gableroux/unity3d:latest   xvfb-run --auto-servernum --server-args='-screen 0 640x480x24'   /opt/Unity/Editor/Unity -projectPath /root/project
Unable to find image 'gableroux/unity3d:latest' locally
latest: Pulling from gableroux/unity3d
6abc03819f3e: Pulling fs layer 
05731e63f211: Pulling fs layer 
0bd67c50d6be: Pulling fs layer 
e59bcdf9f569: Waiting 
b71d75459548: Waiting 
ea0a10bb716a: Waiting 
docker: error pulling image configuration: Get https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/44/44cfb41a0d6ce87f3bf9019a7ed4b40aa20c23d390f0515756c8d07200623b5a/data?verify=1559100714-PcoiRlJ4gKyKppTu7hxHitXjGqs%3D: Service Unavailable.
See 'docker run --help'.

「-v "$(pwd):/root/project"」 を外すと作業を始めた。意味があるかどうかは後で検討。

$ docker run -it --rm    gableroux/unity3d:latest   xvfb-run --auto-servernum --server-args='-screen 0 640x480x24'   /opt/Unity/Editor/Unity -projectPath /root/project
Unable to find image 'gableroux/unity3d:latest' locally
latest: Pulling from gableroux/unity3d
6abc03819f3e: Pull complete 
05731e63f211: Pull complete 
0bd67c50d6be: Pull complete 
e59bcdf9f569: Pull complete 
b71d75459548: Pull complete 
ea0a10bb716a: Pull complete 
Digest: sha256:b84f59091450b89314591dd9e1f51f6aceaf34994b82a7f282b32612b4c36837
Status: Downloaded newer image for gableroux/unity3d:latest 

ここでプロンプトが出ずに止まった。
/bin/bashの指定がないため当たり前かも。

-vの意味を調べる。

やる前に調べろって? ごめんなさい。 DoCAP。

Dockerのすべてが5分でわかるまとめ!(コマンド一覧付き)
https://paiza.hatenablog.com/entry/docker_intro

https://docs.docker.com/engine/reference/commandline/run/

--volume , -v Bind mount a volume

$ docker ps
CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS               NAMES
1f80fb69bfa2        gableroux/unity3d:latest   "xvfb-run --auto-ser…"   7 minutes ago       Up 7 minutes                            priceless_ramanujan
2e7d55f97935        kaizenjapan/100pon         "/usr/bin/tini -- /b…"   4 months ago        Up 4 months                             mystifying_roentgen
KM-S10:~ administrator$ docker stop 1f80fb69bfa2 
1f80fb69bfa2
$ docker run -it --rm   -v "/root/project"   gableroux/unity3d:latest   xvfb-run --auto-servernum --server-args='-screen 0 640x480x24'   /opt/Unity/Editor/Unity -projectPath /root/project

$ docker ps
CONTAINER ID        IMAGE                      COMMAND                  CREATED              STATUS              PORTS               NAMES
54aa8c924989        gableroux/unity3d:latest   "xvfb-run --auto-ser…"   About a minute ago   Up About a minute                       sleepy_rosalind
2e7d55f97935        kaizenjapan/100pon         "/usr/bin/tini -- /b…"   4 months ago         Up 4 months                             mystifying_roentgen
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pleromaのユーザ管理コマンドが変わってた

環境

HostPC Win10

README.mdのままで動きますので、立てる手順は端折ります。

User management

コンテナの中に入って

docker-compose exec web /bin/sh

mix なんとかかんとかシリーズがcould not be found

** (Mix) The task "register_user" could not be found
** (Mix) The task "set_moderator" could not be found
** (Mix) The task "generate_password_reset" could not be found

Admin tasksを参照

  • mix help pleroma.user で一覧表示されました。
## Create a new user.

    mix pleroma.user new NICKNAME EMAIL [OPTION...]

Options:

  • --name NAME - the user's name (i.e., "Lain Iwakura")
  • --bio BIO - the user's bio
  • --password PASSWORD - the user's password
  • --moderator/--no-moderator - whether the user is a moderator
  • --admin/--no-admin - whether the user is an admin
  • -y, --assume-yes/--no-assume-yes - whether to assume yes to all
    questions

## Generate an invite link.

    mix pleroma.user invite [OPTION...]

Options:

  • --expires_at DATE - last day on which token is active (e.g.
    "2019-04-05")
  • --max_use NUMBER - maximum numbers of token uses

## List generated invites

    mix pleroma.user invites

## Revoke invite

    mix pleroma.user revoke_invite TOKEN OR TOKEN_ID

## Delete the user's account.

    mix pleroma.user rm NICKNAME

## Delete the user's activities.

    mix pleroma.user delete_activities NICKNAME

## Deactivate or activate the user's account.

    mix pleroma.user toggle_activated NICKNAME

## Unsubscribe local users from user's account and deactivate it

    mix pleroma.user unsubscribe NICKNAME

## Create a password reset link.

    mix pleroma.user reset_password NICKNAME

## Set the value of the given user's settings.

    mix pleroma.user set NICKNAME [OPTION...]

Options:

  • --locked/--no-locked - whether the user's account is locked
  • --moderator/--no-moderator - whether the user is a moderator
  • --admin/--no-admin - whether the user is an admin

## Add tags to a user.

    mix pleroma.user tag NICKNAME TAGS

## Delete tags from a user.

    mix pleroma.user untag NICKNAME TAGS

## Toggle confirmation of the user's account.

    mix pleroma.user toggle_confirmed NICKNAME

Location: _build/prod/lib/pleroma/ebin
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-composeでpythonを立ち上げてみた(Dockerfile)

概要

いろいろとpythonの環境を考えた結果macではdockerを使ったらいいのでは無いかと思い最初から勉強してみた。

参考

dockerで簡易にpython3の環境を作ってみる
docker-compose コマンドまとめ
あと、公式のリファレンスとか
Compose CLI リファレンス
コンテナで Hello world

ファイル構成

ファイル一覧
├ Dockerfile 
└ docker-compose.yml

Dockerfile

基本的にはpipでインストールするものは最小限のほうが良いとされる。
つまり、何であれ最小構成を心がける。

Dockerfile
FROM python:3.7.3
USER root
SHELL ["/bin/bash", "-c"]
ENV DEBCONF_NOWARNINGS yes
RUN apt-get update && apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm
RUN apt-get install -y vim less
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install  numpy \
                 matplotlib \
                 pandas \

docker-compose.yml

docker-compose.yml
version: '3'
services:
  python3:
    restart: always
    build: .
    container_name: 'python3'
    working_dir: '/root/dev/'
    tty: true
    volumes: 
    - /Users/hoge/dev/python3/:/root/dev/

起動

terminal
$docker-compose up -d --build

停止

terminal
docker-compose down --rmi all

--rmi all でイメージも含めて削除
dockerは短命であるべきらしい

接続

attachもあるみたいだけど、exitすると完全にコンテナが停止するらしいので、基本的にはexecらしい

terminal
$ docker exec -it python3 bash

ps

一番上の参考記事を踏襲した感じになっているので、そちらとの差異を見ていただけたらと思います。
基本的にはDockerfileのみが変わっていると思っていただいて。。。。。
あとは、dockerの基本的な考え方が載っているDockerfile を書くベスト・プラクティスを読むと
コンテナはエフェメラルであるべき
Dockerfile で定義されたイメージを使って作成するコンテナは、可能ならばエフェメラル(短命;ephemeral)にすべきです。私たちの「エフェメラル」とは、停止・破棄可能であり、明らかに最小のセットアップで構築して使えることを意味します。

のようにいろいろな指針が載っています。

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

個人メモ docker

#イメージにリポジトリを追加する
tag
イメージにタグを追加する。
docker tag 元のイメージ名 変えたいイメージ名

inspect

コンテナやイメージの詳細を確認できる。
docker inspect イメージ名

history

イメージに対してしてきた変更を確認できる。
docker history イメージ名

commit

コンテナからイメージを作成できる。
docker commit コンテナ名

build

dockerfileからイメージを作成する。
よくわからなかったので加筆します。

save

イメージをtarアーカイブとして出力。
よくわからなかったので加筆します。

load

saveの出力を復元
よくわからなかったので加筆します。

import

コンテナをtarアーカイブとして出力。
よくわからなかったので加筆します。

login, logout

自分のdockerアカウントにログイン、ログアウト

pull run

レポジトリからのイメージ取得。
docker pull イメージ名

push

レポジトリにイメージを送る。
よくわからなかったので加筆します。

search

レポジトリを探す。
docker イメージ名

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

Docker イメージを ECR に保存して実行する

docker コマンドと aws コマンド (CLI) を使って、手元の Docker イメージを Elastic Container Registry (ECR) に保存して、とりあえずローカルで実行してみます。(2019年5月現在)

リポジトリの準備

先に AmazonEC2ContainerRegistryFullAccess 権限のついた IAM ユーザのアクセスキー ID・シークレットアクセスキーを取得しておきます。

# アクセスキー ID
export AWS_ACCESS_KEY_ID="xxxxxxxxxxxxxxxxxxxx"

# シークレットアクセスキー
export AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# 東京リージョン
export AWS_DEFAULT_REGION="ap-northeast-1"

# Docker を認証する → 「Login Succeeded」と表示されれば成功
aws ecr get-login --no-include-email | sh -v

# ECR 上にリポジトリを作る
aws ecr create-repository --repository-name myalpine

# ECR 上にリポジトリを消す
aws ecr delete-repository --repository-name myalpine

Docker イメージをアップロードする

# 適当なイメージを Docker Hub からダウンロードする
docker pull alpine:latest

# ローカルのイメージの一覧を確認する
docker images

# リポジトリにプッシュするイメージにタグを付ける
# `xxxxxxxxxxx` の部分は、AWS のアカウント ID です。
# `ap-northeast-1` の部分は、リージョン(東京)です。
docker tag alpine:latest xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myalpine:latest

# 間違えたら、タグを消す(リージョンの指定を間違えた等)
docker image list
docker image rm xxxxxxxxxxx.dkr.ecr.wrong-region.amazonaws.com/myalpine:latest

# ECR にイメージをプッシュする。
# 「no basic auth credentials」が出たら認証の問題。リージョンが違うとか。
docker push xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myalpine:latest

# プッシュした ECR のイメージを確認する
aws ecr list-images --repository-name myalpine

# ローカル側のタグをいちど消しておく
docker image rm -f xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myalpine:latest

# ローカル側のタグが削除されたのを確認
docker image list

ECR からイメージをダウンロードして実行する

# ECR 上のイメージをそのまま実行してみる
docker run -it xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myalpine:latest sh

# ECR からイメージをプルする
docker image pull xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myalpine:latest

# ローカルのイメージが復活したことを確認する
docker image list

# ECR 上のイメージの削除
aws ecr batch-delete-image --repository-name myalpine --image-ids imageTag=latest

# ECR 上のリポジトリの削除
aws ecr delete-repository --repository-name myalpine

参考 → https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/ECR_AWSCLI.html

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

docker-compose でコンテナを起動する

docker-compose を使ってミニマムのコンテナを作って起動してみます。(2019年5月現在)

まず最初に、ディレクトリ名が docker-compose におけるプロジェクト名(Docker コンテナ等の接頭辞)になるので、ディレクトリを作ります。

mkdir myproj
cd myproj

Dockerfile を作ります。
ドキュメント → http://docs.docker.jp/engine/reference/builder.html

# 軽量な Alpine Linux をベースにする
FROM alpine

# ログインしたときに便利なように bash・ps・curl を入れておく。
RUN apk add bash procps curl

# 1秒ごとに時刻を STDERR に書き出す
CMD sh -c "(while :; do date; sleep 1; done) >&2"

docker-compose.yml を作ります。
ドキュメント → https://docs.docker.com/compose/compose-file/compose-file-v2/
なお、tty などのオプションについては、docker 側のドキュメント http://docs.docker.jp/engine/reference/run.html を参照します。

docker-compose.yml
version: "3"

services:
  myalpine:
    build: "."
    tty: true

イメージを作ります。
イメージ名は、サービス名の前に、プロジェクト名(ディレクトリ名)が自動で付きます。
プロジェクト名を指定する場合は -p オプションを指定します。

$ docker-compose build
Building myalpine
Successfully built e4215b22f7c8
Successfully tagged myproj_myalpine:latest

$ docker images
REPOSITORY          TAG     IMAGE ID        CREATED         SIZE
myproj_myalpine     latest  e4215b22f7c8    2 minutes ago   13MB

detach モードで起動します。

$ docker-compose up -d
Creating network "myproj_default" with the default driver
Creating myproj_myalpine_1 ... done

コンテナ名は、イメージ名の末尾に _1 が付きます。
起動中のコンテナ・プロセスを確認します。

$ docker ps
CONTAINER ID    IMAGE               COMMAND                   CREATED             STATUS              PORTS               NAMES
cc95a9d44519    myproj_myalpine     "/bin/sh -c 'sh -c \"…"   23 seconds ago      Up 22 seconds                           myproj_myalpine_1

$ docker-compose ps
      Name                     Command               State   Ports
------------------------------------------------------------------
myproj_myalpine_1   /bin/sh -c sh -c "(while : ...   Up      

STDERR 標準エラー出力を確認します。
docker logs だとコンテナ単位のログを、
docker-compose logs だとプロジェクト単位のログを確認できます。
-ftail -f と同じ --follow の意味です。

$ docker logs -f myproj_myalpine_1
Tue May 28 15:13:50 UTC 2019
Tue May 28 15:13:51 UTC 2019
Tue May 28 15:13:52 UTC 2019
Tue May 28 15:13:53 UTC 2019

$ docker-compose logs -f
myalpine_1  | Tue May 28 15:13:50 UTC 2019
myalpine_1  | Tue May 28 15:13:51 UTC 2019
myalpine_1  | Tue May 28 15:13:52 UTC 2019
myalpine_1  | Tue May 28 15:13:53 UTC 2019

稼働中のコンテナにログイン(bash を起動)してみます。

$ docker exec -it myproj_myalpine_1 bash

bash-4.4# uname -a
Linux cc95a9d44519 4.14.114-105.126.amzn2.x86_64 #1 SMP Tue May 7 02:26:40 UTC 2019 x86_64 Linux

bash-4.4# grep PRETTY /etc/os-release 
PRETTY_NAME="Alpine Linux v3.9"

bash-4.4# exit

コンテナを stop で停止してみます。

$ docker-compose stop
Stopping myproj_myalpine_1 ... done

$ docker ps

不要なコンテナを削除して後片付けします。

$ docker image prune -f
Total reclaimed space: 0B

$ docker image list

$ docker image rm myproj_myalpine

今回は1サービスのみでしたが、docker-compose を使うと
1プロジェクトで複数のサービスを束ねられます。

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