sagantaf

なんでも自分の思ったこと、経験したことを書いて生きます。

CNN(Convolutional Neural Network)を理解する

この記事の目的

CNNの理論を理解し、Kerasで実装できるようにするために、理論部分をまとめた記事。

参考にした書籍やサイト


0. 通常のニューラルネットワークの問題

通常のニューラルネットワークにある全結合層では2次元以上のデータを1次元(1列のデータ)に並べ替えて入力している。

そのため、すべての数値を同じものと捉えて学習していた。 この場合、2次元以上→1次元、とデータの次元数を落としているので、数値同士の位置情報が無視されてしまい、学習の精度が上がらない。

f:id:sagantaf:20190526144525p:plain
次元を落として入力するため位置情報を学習できない

そのため、データの位置情報を無視することなく、画像だったら画像の形のまま学習できるように、畳み込みニューラルネットワーク Convolutional Neural Network(以下、CNN)が開発された。


1. CNNの基本

基本的には、データの特徴を畳み込み層であぶり出し、プーリング層で他のデータでも使えるようにぼやかすことを繰り返す。

CNNではConvolutional層Pooling層の2つが一般的に使われる。

Convolutional層とPooling層を適用した後、Affine層を通し、結果を出力する。 例えば下記のような形になる。

f:id:sagantaf:20190526144801p:plain
CNNのネットワーク例

また、後述するDropout層、BatchNormalization層といったレイヤーも使われる。


2. 畳み込み層(Convolutional層)

Convolutional層では、入力データにフィルタ(=カーネルとも呼ばれる)を利用して畳み込み演算を行う。

f:id:sagantaf:20190526144951p:plain
畳み込み演算の流れ

上図の緑色の部分を重ね合わせ、乗算し、全て合計して計算する。

入力画像とフィルタが似たような配置だった場合、乗算によってより数値が高くなり、画像の特徴として抽出できる仕組み。様々なフィルタを適用することで、各画像の様々な場所の特徴を捉えたフィルタ群が完成していく。

畳み込みの処理をしていくにあたっては、  - フィルタのサイズをどうするか  - どうフィルタを適用していくか(ストライド)  - 出力サイズをどうするか(パディング) を決めることになる。

フィルタのサイズをどうするか

フィルタのサイズに厳密な決まりごとはないが、奇数かつ小さいサイズの方が精度が出るため、3×3や5×5がよく利用される。

詳しい解説: https://towardsdatascience.com/deciding-optimal-filter-size-for-cnns-d6f7b56f9363

どうフィルタを適用していくか(ストライド

通常は入力画像に対してフィルタを1つずつずらしながら畳み込み演算を実施するが、ずらす数を設定することもできる。このフィルタを適用する位置の間隔のことをストライドと呼ぶ。

ストライドを1から2や3に増やすことで、大雑把に畳み込み演算することになるため、出力サイズが小さくなり、処理が短時間になる一方で、画像の特徴を取りこぼす可能性がある。そのため畳み込み層ではストライドはあまり使われない。 よっぽどサイズが大きい画像に特徴抽出したい対象が大きく写っている場合は、ストライドを適用しても特徴を失うことなく効率的に処理ができる。

逆に、後述するPooling層ではストライドは積極的に利用される。

出力サイズをどうするか(パディング)

入力データの周りに固定データを合わせることで入力のサイズを大きくし、出力サイズを調整することができる。 これをパディングと呼び、画像のはじの特徴も捉えることができる、出力サイズが小さくなって演算ができなくなることを避けられる、といったメリットがある。 周辺を0で埋める「ゼロパディング」がよく利用されるが、この場合、周辺が暗くなってしまう。それを回避するために、周辺の画素数をそのまま外挿するパディング方法なども存在する。

データ形状の変化

入力時のデータ形状は [縦×横×チャネル数(色の数)] になる。

28×28のサイズのRGB画像であれば、 28 × 28 × 3 になる。

この入力画像に適用するConvolitional層として、
 3×3のフィルタを32枚、ストライド1、パディング1
を設定した場合、畳み込み処理後のデータのサイズは 28 × 28 × 32 となる。

つまり、畳み込み層の出力は、 [縦×横×フィルタ数] となる。

ただし、フィルタサイズ、ストライド、パディングの設定値によっては計算ができない場合もあるため、注意する。

たとrば、10*10の入力画像に対してフィルタが3*3でストライドを3にした場合だと割り切れないため、場合によってはエラーになる(ライブラリによっては自動で可能な部分だけ計算してくれるものもある)。

畳み込みまとめ

畳み込み層は画像の特徴を抽出するためのレイヤーになっている。そのため、畳み込み層を2つ連続で続けるなど、レイヤーを増やすと、1つ目に適用した結果に対して2回目の畳み込みをするため、より小さい特徴を捉えられるようになる。

ネットワークを深くして精度が上がった有名なネットワークもある(AlexNet,VGGなど)。

ただし、深くしすぎると勾配消失問題が起きたり、過学習したりするという別の問題が発生するため、別途対処が必要になる。


3. 活性化関数について

畳み込み後の活性化関数は、勾配消失問題に対応するため ReLU が使われることが多い。

ReLUは正の値をそのまま出力し、マイナスの値は0にしてしまう関数。 畳み込み処理後のデータは特徴が正の大きな値となって現れてくる。そもそもマイナスの値である部分は特徴としてフィルタリングされなかった部分であるため、0にしてしまっても問題ない。


4. プーリング層(Pooling層)

畳み込み層で浮き出てきた特徴をぼやけさせ、他の似たような特徴と同じとみなして学習させることを目的としている。

そうすることで同じものが写った別の画像でも特徴を検知できるようになる。(汎化能力アップ)

同様の理屈で、プーリング層の出力には活性化関数を適用しない。活性化関数を使うと特徴を際立たせることになってしまい、ぼやかした意味がなくなってしまう。

プーリングの手法は、最大プーリングや平均プーリングが代表的。ただし、効果の違いなどまだ不明なことも残されている。

また畳み込み層と同じくストライドを設定して計算することもできる。ぼやかす機能として役に立つため、畳み込み層とは違いストライドを2以上に設定することが多い。


5. CNNの特徴

CNNの特徴は下記2つある。 ・局所受容野(local receptive field):   全結合とは違い、特的のユニット同士のみが結合されるため、局所的な特徴を学習できる。また、データの形状も特徴として捉えることができる。 ・重み共有:   1種類の画像(縦-横-チャネル)に対しては同一の重みとバイアスを共有し適用するため、似た特徴を捉えやすい。どこにあってもきちんと特徴を抽出できるようになる。また、パラメタが減り全結合層よりも計算時間が短縮できる。どちらも学習効率が良くなる効果が得られる。


6. そのほか利用される層

Dropout層

学習に必要なエポック数が増えるが、過学習を抑制できる。

BatchNormalization層

平均0分散1に正規化する層。正規化によって、

  • 学習が早くなる
  • 初期値にあまり依存しない=初期値にロバスト
  • 過学習を抑制する(Dropoutなどの必要性を減らす)

といった利点が生まれる。

また、Dropout層と併用するときには注意する。逆効果になる可能性がある。 参考ページ:https://github.com/arXivTimes/arXivTimes/issues/608

このBatchNormalizationは、データ数が多くパラメタが少ないような過学習しにくいモデルの場合は不要。(逆にない時よりも精度が悪くなる可能性がある)


7. CNNの設計

捉えたい特徴を確認し、最初は基本的な形からスタートする。

その後、少しずつ変更してみる。

ネットワークを深くしたり、Augmentationをしたり、Dropout層やBatchNormalization層を追加したり。

下記のような記事を参考に過去の精度の高いネットワークで試すのもあり。

https://qiita.com/skyzhao/items/7f23962d9cfac51328d3

https://www.slideshare.net/ren4yu/ss-145689425


8. CNNの精度向上のために考えること

まずはデータを疑う。データがきちんと整っていないと、どんなにアーキテクチャーやハイパラメタを調整しても精度は上がらない。

入力データの問題

  • 画像サイズは一定か
  • 画像サイズに対して対象が小さすぎないか(小さすぎると特徴が捉えられない)
  • 反射したりして特徴が複雑になっている画像ではないか(パターンが捉えられない=もっと画像が必要になる)

アーキテクチャの問題

  • ぼやかすタイミングがあっているか?畳み込みでstrideしていないか?
  • 過学習していないか?しているのであれば画像の枚数を増やす、Dropoutする
  • 逆に過学習を避けようとしてDropoutやBatchNormalizationをつけすぎていないか(DropoutをConv層はやめてDense層だけにしてみるとか)
  • DropoutとBatchNormalizationを併用していないか
  • レイヤーが少ない方が精度が高くないか?(勾配爆発消失)

上記の問題を考えてみた上で、

  • ネットワークを深くする  畳み込み-ReLU-Pooling のセットを増やしてみる。

  • Augumentationする  画像を回転させたり、拡大させたり、反転させたりして同じ画像を複数枚に増やす。

を実施してみることで精度が上がることもある。

TensorflowをGPUで使おうとして「CUBLAS_STATUS_NOT_INITIALIZED」というエラーが出たら

環境:

  • Docker上でubuntu16.04のコンテナを起動
  • GPU:TITAN V
  • nvidia-driver: 390
  • cuda: 9.1

という感じ

tensorflow-gpuをインストールした時に、下記のエラーが発生。

E tensorflow/stream_executor/cuda/cuda_blas.cc:366] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED

W tensorflow/stream_executor/stream.cc:1901] attempting to perform BLAS operation using StreamExecutor without BLAS support

ググると「GPUのメモリが不足しているとか解放されていないからプロセスを落としたり再起動せよ」って書いてあるけど、解決しない時がある。

そんな時はメモリが原因ではなく、キャッシュやtensorflowの設定に問題がある。

以下を実施することでエラーは発生しなくなり問題なくインストールできた。

キャッシュファイルの削除

$ sudo rm -rf ~/.nv/

tensorflowの設定変更

$ python
>>> import tensorflow as tf  
>>> from keras.backend.tensorflow_backend import set_session  
>>> config = tf.ConfigProto()  
>>> config.gpu_options.allow_growth = True  
>>> config.log_device_placement = True
>>> sess = tf.Session(config=config)  
>>> set_session(sess) 

「config.gpu_options.allow_growth = True」の設定で、GPUのメモリを状況に応じて変更してくれるようになる。

「set_session(sess) 」で修正を反映できる。

アクションバイアス〜目標を持って仕事を進める人間になるには

アクションバイアスという本を読んで、目標を持って仕事を進めていくための方法を自分なりに理解して解釈したので、その内容を残す。

アクション・バイアス: 自分を変え、組織を動かすためになすべきこと

アクション・バイアス: 自分を変え、組織を動かすためになすべきこと


本書は、「目的意識を伴う行動をとれる人間になるにはどうするか」「どうすることで、目的を常に意識して行動することができるか」について書いてある。

簡単に言うと、
 目標に対するエネルギー・やる気を高め、個人の強い決意、強固な意思に集中することで、気を散らすものを追い払い、問題を克服し、挫折してもやり抜き、目標を達成することができる
という内容




目次

エネルギーを高めるには

目標を明確にする

 目標は、達成する自信があり、明確であり、意欲的であることで意味を持つ。
 そんな目標を定めるために以下の項目を確認する。

 ・目標はどのような要素により構成されているのか、それを達成するためにはどのような障害を乗り越える必要があるか
 ・その目標を追求することが、自分にとって価値のあることだと確信しているか、またそれが組織の利益にもなると同時に確信しているか
 ・圧倒されて最初から何をしたら良いかわからないような目標になっていないか。達成可能だと感じられるか。

 達成したいと思う、自分の感情を揺さぶるような目標を見つける。最初は漠然としていても、よく考え抜き、疑念や不安を解消させ、明確に頭の中にイメージを描く。そうすることで頭でも心でも目標を達成できると確信できる。
 また、事前に目標達成の状態、中止とする状態を明確に定めておき、このルールに従うことも、猪突猛進にならないために必要になる。

感情をコントロールする

 考えや感情に圧倒され、抑え込むと、不安や怒りが、やがて不満やあきらめに変わってしまう。
 前向きな態度をとるための方法として、
 ・内面の緊張や辛い気持ちをうまく処理する方法を知る(人に話したり全く別のことをやったり様々)
 ・定期的にエネルギーを補充する(趣味に興じたり、特別な場所へ行ったり)



目標に集中するためには

頭の中に自分の意図を描く

 目標や意図や具体的な行動イメージを頭の中に鮮やかに描いておくことで、障害にぶつかった時や横道に逸れそうな時に、描いたイメージが心の支えとなる。
 また、集中を阻害する主な要因は、新しいことをする、既存のものを変更する、障害にぶつかる、やることが多すぎて考える時間がないなど。これらに対する対処(障害にぶつかったらどうするか、気が逸れたらどうするか、など)を自問する。

自分の意図に個人的なコミットメントをする(決意する)

 自分自身が最終的に結果を左右するということを認識する個人的なコミットメント=決意をすることで集中力が高まる。(責任感を高める)
 ただし「誰が自分に何を期待しているか、評価されるだろうか、自分にはどんな利益があるのか、合理的か」と行った理性的な分析による決意だけでは、今よりも良い仕事や他のアイデアが出てきたときに簡単にぐらつき、横道に逸れてしまう。
 仕事についての理性的な分析と、感情的な願望が一致した時に決意が強固なものになる。
 定期的に時間をとって内省し、自分は本当にそれを望んでいるかを自問する必要がある。自問の内容として、「その目標に心踊るか」「逆境に立たされても持続できるか」「自分の価値観や信念に合致するか」「目標が達成できなかったらどう感じるか」「達成したらどう感じるか」「どのような障害に直面するか。どう対処できるか。」「どんな感情、イメージが自分の前向きな行動を促すか」など。

目標から気を逸らさせる感情に対処する

 気を逸らさせるような対象を、魅力がないものへとイメージで変えてみる。
 疑念やイライラなどの感情を認め、周りに話す。
 ネガティブな感情をポジティブに捉える(ユーモアで包み込んだり笑い話にしたり、プライドを掻き立てたり)


モチベーションではなく意志力

今まで書いたプロセスを経ることによって、モチベーションを高めるというレベルではなく、強固な意志力を持って目的に邁進できるようになる。
モチベーションは、何かに関与したいと願ったり、何らかの機会に惹かれたり、何らかの行動をとりたい気持ちになるといった状態であり、環境の変化や内面の嗜好の変化に影響されやすく、不安的なもの。
意志力は、まず目的や使命があり、それに対して考え抜き、疑念や不安を解決しているため、疑いの余地なく突き進むことができるもの。また障害にぶつかっても克服するための方法を考え抜き、失敗するという選択肢が出てこない。


行動を阻む罠

上記を実現できたとしても陥ってしまう行動できなくなる罠が3つある。

圧倒される要求

日常の仕事に圧倒されることで、自分の目標を振り返り、何が重要かを自問できず、何も達成できない状態に陥ってしまう。
そうならないように仕事の要求をコントロールする方法として以下を実施する。

・自分個人のアジェンダを作成する
 仕事上で成し遂げたいと思うこととその方法について、アジェンダとして明確に考えをまとめる。そしてそのアジェンダに沿って仕事を進めることで、毎日の仕事が長期的な目標に向かっていると実感し、意欲を掻き立てることができる。意志力の強化につながる。

・全てをやろうとしない
 全てをやろうとすると二兎を追う者は一兎をも得ずになる。実施する仕事を吟味して取捨選択する。また選択した仕事について優先順位をつけてから手を付ける。

・要求に働きかけ、自分への期待を管理する
 他人の期待や要望全てに答えようとすると自分のアジェンダを追求する時間がなくなり、上記と同じく二兎を得ず状態になる。アジェンダの主要な利害関係者に注意を集中させるべき。

・人と接する時間を決めておく
 人とのやりとりは、時間がかかるだけではなく、頭を何度も切り替えることで意志力が削がれる。一日のうち接する時間の上限を決めておく(打ち合わせ時間や依頼対応など)。

耐えられない制約

規則や規制、制約があるために自主的に行動をとる余地がないと信じ込み、意欲を失ってしまう。
そうならないように自分を制約から解き放つための戦略として以下を実施する。

・制約の地図を作成する
 時間や意欲を奪っている規則規制や、前進することを阻む壁となっている制約などを言語化することで、対処法を具体的にイメージできるようになる。

トレードオフを受け入れる
 「なくてはならないこと」と「あればいいと思うこと」を峻別し、前者に対しての制約と闘うことに注力する。全てに対応できないことを理解し、「あればいいと思うこと」を捨てる必要に迫られた時には捨てる。

・規則を選んで破る
 時には許可を得るよりも後で謝る方が良い。自分の目標達成のために邪魔になるならば、規則を破るか回避する方法を考えるか、規則自体を変える。
 規則を変えるには、規則がある理由を考え、無くしたり変えたらどうなるのかをイメージした上で、周囲の人を巻き込んで議論する。

模索しない選択肢

仕事の要求と制約に目を奪われ、視覚狭窄に陥り、目の前のニーズや要求に専念してしまう。 そういったことに陥らないようにするために以下を実施する。

・選択ができることに気づく
 選択肢を持つことは選択することよりも重要。自らの意思で選択し、行動していることになり、意志力の向上につながるため。  選択肢は常に明快であるわけではないため、仕事上で「できない」と自分が認識していることは何か、を自問し、「一体誰が、何がそれを阻害しているか、それを行なったらどうなるか」をイメージする。

・選択肢の幅を広げる
 自分の目標を達成するためには何が必要になるのか、どんな方法があるのか、1つしか方法はないのか、を自問する。複数の選択肢を持っておくことで、必要に迫られた時にいつでも切り替えることができる。
 また、他の人に相談したり、自分の気持ちを上司と率直に話し合うことで、他人の意見や見方を知り、選択肢の幅を広げることもできる。

・個人の知識と能力を高める
 絶えず自らの知識を積み、能力を広げ、深掘りする。
 自分自身の仕事のみに注力し、広げること(他人の関心ごとや姿勢を理解することも含む)をしないでいると、視野が狭くなり他人への感情移入ができない。つまり自分がやりたいことを他人に提示、説得することがうまくできない。

pandas〜欠損値扱いの数値をNaNに変換する

-1や999など欠損値として格納されているデータをpandasのreplaceを使ってNaNに変換する方法を書く。


サンプルデータフレームの作成

まずはサンプルのために簡単なデータフレームを作成する。
欠損値は、-1, 999, 1000とする。

import pandas as pd

df = pd.DataFrame([[1,2,-1,4,5],[1000,5,6,999,8]],['a','b'])

dfは以下のようになる。

0 1 2 3 4
a 1 2 -1 4 5
b 1000 5 6 999 8



欠損値をNaNに変換する

pandasのreplaceメソッドを利用して変換できる。

df2 = df.replace([-1, 999, 1000], np.nan)

df2は以下のようになる。

0 1 2 3 4
a 1 2 NaN 4 5
b NaN 5 6 NaN 8

文法は
 df.replace(変換したい対象, 変換後のデータ)
と書き、変換したい対象はリストを指定することも可能。

他に例えば0に統一したい場合は、

df2 = df.replace([-1, 999, 1000], 0)

とするだけ。



元のデータフレームを変更してしまう

先ほどのようにdf2をわざわざ作成せずに、元のdfを書き換えてしまうにはオプションとしてreplaceをつけるだけ。

df.replace([-1, 999, 1000], np.nan, inplace=True)

これでdfが直接変換される。



pandas〜データフレームをpickleファイルとして保存し効率的に開発する

pandasでデータを読み込んで色々手を加えたデータフレームをpickleファイルとして保存(ダンプ)する方法を書く。

毎回 jupyter-notebookを開いたときに最初から実行せずに、保存しておいた編集済みのpickleファイルを読み込むことで、かなりの時短になる。



サンプルデータフレームの作成

まずはサンプルのために簡単なデータフレームを作成する。

import pandas as pd
import joblib

df = pd.DataFrame([[1,2,3],[4,5,6]],['a','b'])

dfは以下のようになる。

0 1 2
a 1 2 3
b 4 5 6



データフレームの保存

joblib.dump(df, './sample.pkl')

joblib.dumpという関数を利用して、データフレームをファイルとして保存できる。 上記の場合、.pyファイルを実行、もしくはjupyter-notebookを起動したカレントディレクトリにファイルが保存される。



データフレームの読み込み

df2 = joblib.load('./sample.pkl')

df == df2

joblib.loadという関数を使うことで、ファイルの中身をデータフレームに格納できる。 結果は以下のように表示されるはず。

0 1 2
a True True True
b True True True



Rancher入門〜インストールと基本的な使い方


コンテナ管理のためのGUIであるRancher バージョン2 の導入方法と使い方をまとめておく。


目次

はじめに

Docker自体のインストールは以下に記載。
sagantaf.hatenablog.com
Rancherの詳細は以下を参照(公式ページ、英文)
Overview | Rancher Labs


今回検証した環境は、  

  • Ubuntu 16.04  
  • Docker 18.06.1-ce

    RancherはDocker for Mac と Docker for Windows には未対応らしい。

    Rancher Management Server を起動

    以下のコマンドを実行し、Management Server(以下、managementマシン)を起動する。

    sudo docker run -d --restart=unless-stopped --name=rancher_master  -p 8001:8080 rancher/server


    オプションの詳細は以下:
     -d →コンテナをバックグラウンドで実行する
     --restart=unless-stopped →明示的に停止したとき以外には再起動する
     --name=’NAME' →コンテナにNAMEという名前をつける
     -p 8001:8080 →8001などホストポートを指定する(8080はコンテナのポート。8080じゃないとrancherに繋げられない)

    実行後は、ブラウザで

     http://<コマンドを実行したマシンのIPアドレス>:8001

    にアクセスすることでGUIページを開ける。

    ただし、アクセスできるようになるまで2〜3分かかる。

    f:id:sagantaf:20181230223027p:plain
    Rancher起動時の画面


    上記のように最初の画面が現れたら、「Got it」を押して、上のバーに出ている「Add a host」へ。

    ホストマシンをRancherの管理対象として追加

    最初にmanagementマシンのURLを設定する画面が出る。ここで指定するURLは、追加したいホストマシンからアクセスできるURLである必要がある。localhostなどになっている場合はアクセスできないのでIPアドレスに変更しておく。

    f:id:sagantaf:20181230233459p:plain
    URL設定画面


    「Save」して次のページに行くと、AWSインスタンスやAzureのインスタンスなどを選択できる。
    ここでは「Custom」のまま、4 に追加したいIPアドレスを入力する。

    f:id:sagantaf:20181230225454p:plain
    Add Hostのページ

    5 に書いてある自動で作成されたコマンドをコピーして、追加したいホストマシン上で実行する。
    実行した結果、ホストマシンのコンソールに「INFO: Launched Rancher Agent: XXXXXX」の文言が出力されたらOK。

    少し時間を置いた後に、ホスト画面にホストが追加されていればOK。

    いつまで経ってもホストが追加されない場合はエラーが出ている可能性がある。 ここではDNS設定ができておらず、Managementマシンと通信できていない場合の対処方法を記す。

    追加したいホストのDocker設定を追加する

    追加したいホストにログインし、dockerの設定ファイルを編集する。

    sudo vim /etc/docker/daemon.json

    以下の文言を追加して保存する。

    {
        "dns": ["8.8.8.8", "8.8.4.4"]
    }
    

    rancher-agentとdocker自体を再起動

    docker stop rancher-agent
    sudo systemctl restart docker
    docker start rancher-agent

    これを実行した後にRancherのGUIでホストが追加されていることを確認する。

    RancherGUIへのアクセス制限を設定する

    無事、ホストが追加されたら、いよいよコンテナを追加、、、の前に簡単なセキュリティ対策をしておく。

    Rancherは最初に起動したままでは、誰でもURLにアクセスすればGUIを触れる状態になっている。
    ここではアクセス制限として、管理者のみがアクセスできるようにするために、ユーザとパスワードを設定する。

    一番上のバーから ADMIN > Access Control と移動すると以下の画面になる。

    f:id:sagantaf:20181230231626p:plain
    Access Controlのページ

    LOCALを選択して、必要な情報を入力したら、「Enable Auth」を押して有効化する。

    設定できたかを確認するために、一度ログアウトする。
    以下の認証画面が表示されたらOK。
    (ついでに日本語に変えておいた)

    f:id:sagantaf:20181230232025p:plain:w200
    ログイン画面

    カタログからコンテナを追加する

    ここではWordPressをお試しで構築する。
    上のバーのスタックから、「カタログを参照」へ移動する。

    f:id:sagantaf:20181231084018p:plain:w300
    スタック初期画面

    検索窓でwordpressと検索して「詳細を見る」へ。

    f:id:sagantaf:20181231084305p:plain
    カタログ検索画面

    詳細画面ではとりあえずデフォルトの値のまま「起動」を選択する。
    起動した後は、2〜3分で左から右の状態になる。

    f:id:sagantaf:20181231084828p:plain:w220   f:id:sagantaf:20181231085122p:plain:w220
    起動後の状態

    全てActive状態になったら、ブラウザから
      http://<追加したホストのIPアドレス>:80
    にアクセスすることでWordPressのテンプレート画面が表示される。

    例)http://192.168.123.1:80

  • Docker入門〜dockerとdocker composeをubuntuにインストールするためのシェル

    タイトルの通りdockerとdocker-composeをubuntu16.04環境に一気にインストールしてしまうためのシェルを作成しました。

    #!/bin/sh
    
    # まずは必要なパッケージをインストール
    sudo apt update
    sudo apt install -y \
        apt-transport-https \
        ca-certificates \
        curl \
        software-properties-common
    
    # Dockerのリポジトリの追加
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    sudo add-apt-repository \
       "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
       $(lsb_release -cs) \
       stable”
    
    # Dockerのインストール
    sudo apt update
    sudo apt install -y docker-ce
    
    # docker-composeのインストール
    sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
    
    # docker-composeの実行権限を追加
    sudo chmod +x /usr/local/bin/docker-compose
    
    # 最後にバージョンを確認
    docker  --version
    docker-compose --version

    実行結果の出力として、dockerとdocker-composeのバージョンがそれぞれ出力されたら成功です。

    シェルファイルにせず、コマンドを1行1行実行していっても大丈夫です!