【勉強編】dockerにLaravel環境を作るまで

Twitterで冬休みの間にポートフォリオを作ると宣言して一応設計書までは準備したのだが、
dockerでLaravel環境を作ろうとして結局挫折した。

とはいえ作らないとポートフォリオ自体いつまでも作れないので、docker自体を勉強し直すことに。
（冬休みには作れなかったけど、せっかく設計書書いたのでポートフォリオ自体は最後まで作成します）

詰まったのはどこかというと、
DockerFileを作るまでは良かったけど、そこから `docker-compose`コマンドを実行しようとしたところ。

そんなわけで復習も兼ねて上のコマンドを実行できるようになるまでここに書き連ねたい。

## 基本的なコマンド

### dockerをnginx環境で起動（例）

※nginx　・・・エンジンエックスと読む。いわゆるWebサーバーの一種
　　　　　　　えーとニジンクスかなと推測して読んでたら全く違う読み方だった。。。
　　　　　　apacheもアパッチェと思ったらアパッチだったし(ただし、コマンド上は`httpd`)

nginxの場合
```
docker run -p nginx
```
Apacheの場合
```
docker run -p httpd
```

[>>> dockerドキュメント](https://docs.docker.jp/engine/reference/commandline/run.html)
※ -p（ポートの略、ポート公開ということ）とかのオプションの説明はドキュメントを見た方が早い。
※ どの環境でrunできるかは、[dockerhub](https://hub.docker.com/)で検索しよう（ついでにログインもできるように新規登録もしておこう）
※ [https://labs.play-with-docker.com/](https://labs.play-with-docker.com/)　で、dockerの実験ができるので、勉強がてら触れる(docker-hubのログイン必須）

### docker　停止
コマンドライン上で `ctrl`(Macだと`control`) + `c` で停止
コマンド上でもshutting downなどの反応があり、閉じてることがわかる

### Docker imageをpullしてdocker上で動かす

Docker　imageはdockerに入れるOSとかソフトウェアとかPHPとかのランタイムを全てをパッケージ化して保存したようなもので環境のスナップショットというらしい。
つまりこれをpullしたらdockerでインストールが始まり、その後は何も設定しなくても動かせるようになるというもの。

前に紹介したDocker Hubでは、こういうDockerimageがたくさん公開されている。
例えば php　だったり、ubuntuだったりもDockerHub上から取得できるが、Webサイトにいかなくてもコマンド上でもpullできる。(`docker pull (取得したいツール名）`)
見つからない場合は`docker search (取得したいツール名)`　で検索
（OFFICIALにOKとあるのがDocker公式のもの）

例えばphpならこれ
```
docker pull php
```
ubuntuを検索するならこれ 
```
docker search ubuntu
```


OSでもランタイムでもソフトウェアでもいける。（ubuntuとか）

### Dockerfileを作成してアップロードして動かす

さてある意味本題。　

DockerfileとはDockerImageを作るための設計書みたいなもの。
これを自分で作って実際にやってみてOKかどうか確認しながら調整していく。

ここで色々躓いているので、躓きやすいポイントから。

まずそもそも、Dockerは１つの大きなフォルダ単位のフォルダで、
その中でOSなり、ソフトウェアなり、ランタイムなどが動く。
そのためフォルダ内にOSのフォルダだったりランタイムのフォルダがサブフォルダとして置かれている。

dockerが動かない原因で一番多いのは　dockerFileが置かれているフォルダを間違えていること。
Laravelと同じで、置かれているフォルダにdockerFileがないとdocker自体が動かない。
ディレクトリの位置だったり、パスだったりが重要。

#### １. ディレクトリ周りの整理
とりあえずubuntu環境作ってコマンドでhello dockerworld!と出力するまでやる
というわけでいきなりコマンド（macなのでWindowsは適宜読み替えてください）
１行ずつやってもいいし、全部コピペして貼り付けてもOK

```
cd ~
mkdir -p DockerOS/ubuntu
cd DockerOS/ubuntu
echo "hello dockerworld !" > helloworld.txt
vi Dockerfile
```
（説明）
1行目：　cdでホームティレクトりに移動
２行目： mkdirはディレクトリを作るコマンド、-pはサブディレクトリも作っちゃうオプション、
　というわけで、dockerフォルダ、その中にubuntuフォルダも一気に作っちゃう
３行目: 一気にubuntuフォルダまで移動
4行目：　(コマンド） > helloworld.txtというファイルに（コマンド）を記載
５行目：　Dockerfileを作り、さらにviを起動（コマンドライン上のエディタ）

（実行後）
viが起動し、コマンド上でDockerfileの編集画面になる
普段のコマンドラインと違うところとしては、左端に行番号が現れるところ。

＊＊＊＊
次に、Dockerfileの編集画面で、

```
FROM ubuntu
COPY helloworld.txt /tmp/helloworld.txt
CMD ["cst" , "/tmp/helloworld.txt"]
```
とうち終わったら`esc`を押して編集終了し、
さらに`shift` を押したまま、 `z`を２回押せば（つまり大文字の`Z`キーを２回押すということ）
上書き保存して終了し、元のコマンドラインに戻る。

編集できているのを確認する。
※もしescを押しても返答がない場合はやり直した方がいいかもしれません。
　私の場合はやり直していけました
※viの操作がわからなければ、普通に新規テキストファイルで上の文章を入れて保存する、でも良いです。でも慣れれば短い場合はこっちの方が早くできるので、練習の意味でもやってみた方がいいかと。

これでディレクトリの準備はOK

#### 2.Dockerimageの作成（ビルド）と、実行
いきなりコマンドから。
※cdはDockerOS/ubuntuのところにいる状態のまま。もし他の場所に移動してしまったら、cdでubuntuのところまで移動しておく。

```
docker build -t helloworld .
```
Dockerfileから作るDockerImageを「helloworld」にするという意味で、
最後の「.」は打ち間違いではなく、COPYコマンドを実行するときにどのディレクトリを起点にするかを指定するもの。
この場合、dockerfileがあるフォルダということになる
実行してerrorが出なかったら、dockerimageがビルドできたか確かめる
```
docker images
```
リストにあったらOK

次に、イメージからコンテナ作成実行
docker run　の後に追加したRepository名を入れる（上のdocker imagesで出てきたもの）
```
docker run helloworld
```
そうすると、
hello dockerworld!というのがコマンドラインに出力され、完了



#### 3.DockerHubへのアップ

ローカルで開発したイメージをステージングや本番環境で動かすには、DockerHubにアップして置かないといけない。ログインとか新規登録したのはこのため。

※クラウドの場合だとどうやらレジストリサービスがあるので、AWSとかGCPではマニュアルをみたほうがいい。後で確認する

`docker login`でユーザ名とパスを入れてログイン。
（メールアドレスだとダメでユーザ名でないといけないらしいです。マイページに出てくるアカウントの名前を入れればOK。)

Docker hubにアップロードするときには、下記のようにする
```
docker tag helloworld <ユーザ名>/helloworld

例）ユーザ名が９９９hogehogeだったら
docker tag helloworld ９９９hogehoge/helloworld
```
dockerimageの確認＝＞コマンドは？　わからなければ上を見て復習

次に、アップロード

```
docker push <ユーザ名>/helloworld

例）ユーザ名が９９９hogehogeだったら
docker push ９９９hogehoge/helloworld
```
終わったら、[Docker Hub](https://hub.docker.com/)の確認
レポジトリにアップしたのがあるか見ておく

Docker HubにアップしたDocker Imageの実行
→ 現在のローカルイメージを削除しないとDockerHubから取得ができないため

```
docker container ls -a
docker container prune
docker image prune -a
```
　　lsは参照、-aは全てという意味。
pruneは削除.（２行目はコンテナ、３行目はイメージから）

dockerのイメージがもう全部残ってないか確かめるには？
わからない時は上を見て復習

次にDocker Hubから作成したイメージを取得するには
```
docker pull <ユーザ名>/helloworld
```

次にdockerイメージの実行
```
docker run <ユーザ名>/helloworld
```
Hello, dockerworld!
が表示される
ここで基本的な流れは完了

### Dockerfileで使うコマンド

17コマンドしかない
中でもよく使うのは７つぐらい

基本的にベースとなるDockerImageをDockerHubから調べて持ってきて、その上にCOPYやRUNを加えてDockerImageを使う。

`FROM`　ベースとなるDocker Image（例：node/php/ignix/httpdとか）　

`COPY`　ホストのファイル・ディレクトリをコピー　引数１がホスト側ディレクトリ（`docker build .`
で指定したディレクトリ）、引数２がDocker側ディレクトリ（`WORKDIR`で定義したディレクトリ）

`RUN`　コマンド実行（コンテナへ依存するライブラリ、パッケージのインストール・ユーザ設定などの処理）

`CMD`　Docker起動時にデフォルトで実行されるコマンドを定義。なお、フォアグラウンドで実行するように定義しなければならない。（バックだとすぐ止まるため）

`WORKDIR`　コマンドを実行する時基準となるディレクトリを設定。存在しなければ作成する。
→既存のディレクトリを上書きする場合もあるので注意

`ENV`　Docker内での環境変数を定義 

`USER`　作成したDockerImageを起動ときにログインするユーザーを指定。デフォルトが`root`なので他のユーザーを指定すること。

`ADD`　COPYの拡張版。COPYと同じく指定したパスをコンテナ内にコピー、URLを指定したらそのURLからファイルをDL,コンテナ内にコピー、コピーされたパスが`.tar系`だったら解凍するという３つの役割がある 第１引数はコピーしたいファイル名、第２引数はコピー先のパス。コピーしたいファイル名

それ以外だと
`EXPOSE`コンテナ起動時に公開することを想定しているポートを記述しておく。
また、EXPOSEで指定されたポートを公開するには `run -P ...`とする
`AGES`Dockerfileのビルド時に変数を使用するためのコマンド。基本的に使用しない
`ENTRYPOINT`指定されたコマンドを実行。`docker run`時に指定したコマンドをこのコマンドの引数として使用。普通の場合、CMDを使うので、そうでないと初心者が混乱するため使用しない方がいい
`VOLUME`Data Volumeを作成するコマンド。

以下は必要になった時、見た時に覚えよう

`ONBUILD`
`LABEL`
`STOPSIGNAL`
`MAINTAINER`
`HEALTHCHECK`
`USER`
`SHELL`


では今回の原因になったDockerfileの中身は

```

FROM php:7.4-apache

# 設定ファイルをdockerコンテナ内のPHP、Apacheに読み込ませる
# ADD：ローカルのファイルをDockerコンテナ内にコピーする
ADD php.ini /usr/local/etc/php/
ADD 000-default.conf /etc/apache2/sites-enabled/

# Composerのインストール
# RUN：コンテナ内でコマンド実行する
RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer

# ミドルウェアのインストール
RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim \
libpng-dev \
libpq-dev \
&& docker-php-ext-install pdo_mysql

# Laravelで必要になるmodRewriteを有効化する
RUN mv /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled
RUN /bin/sh -c a2enmod rewrite

```
問題となった箇所だが、ファイルのパスが怪しい気がする。

## そもそもの原因

とりあえず、phpのパスを確認しようと思って
```
php -v
```
と打ってみたが、phpがなかった。。
　
Macには必ず入っているはずなのに、、、と思っていたら、どうやら、いつのバージョンかわからないか自動ではインストールされなくなったらしい。なるほど。
だとしたらそもそもphp.iniがないからコピーできなかっただけやんこれ。

原因判明。

phpをダウンロードするとなって、はたと気づいた。
元々、phpは８.0以上だったので、そもそもこのdockerfileじゃだめだった。

全部ダメじゃん。。。

気を取り直して、
dockerhubで、docker laravelで検索したら、
公式のいいdockerfileが出てきたので、このイメージを使ってインストールして、
LaravelでWebサーバーが立ち上がったので、URL（localhostのやつ）
に繋いだら、いつものLaravelのロゴが出てきた。

これにて完了。

まあ、遠回りしたけど、dockerのことが学習できたし、わかっただけでもよしとしよう。

## 原因と今後の課題

・dockerfileの各文章の意味が分かってなかった
・ローカルPCにphpが入っていないことに気づいてなかった（普段ローカルPCでなくてテスト環境で開発してたので。。。それそもそもあかんけど。。。）
・何よりdockerに慣れてなかった

ということで。dockerは便利なのでエンジニアは一緒に使えるようになろうぜ。
と何気にカッコつけてみる。

以上。