（確認用）AWSのECRのイメージを使ってdockerでLaravelのイメージを作成する手順

個人メモです。

AWSのECRレポジトリに保存したイメージを使って、Laravelのプロジェクトイメージをローカルに作成（build）する手順の確認。

aliasでコマンド一つでイメージを作成しているがその中身について。


```sh:.aliases.sh
# stg
alias cs-stg-build="cs-pull-base-image && cs-login-aws && cs-envvars docker-compose build php-fpm stg"
```

##処理の概要

1. dockerがAWSのECRレポジトリにログインできるようユーザー名とPWを渡す。
2. AWSのECRレポジトリからベースイメージをpullする。
3. プルしてきたイメージに名前をつける
4. php-fpmのイメージを作成する
5. php-fpmをベースイメージとしてプロジェクトのイメージをマルチビルドで作成する

以上でコンテナ起動用のイメージが完成。



<br>
##1. cs-pull-base-image

```sh:cs-pull-base-image
alias cs-pull-base-image="cs-login-aws && \
  docker pull 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/docker-base-images:php-fpm-grpc-f1 && \
  docker tag 11111111111.dkr.ecr.ap-northeast-1.amazonaws.com/docker-base-images:php-fpm-grpc-f1 cl_php-fpm-grpc:f1"
```

この中に、`cs-login-aws`、`docker pull`、`docker tag`
の３つのコマンドが入っている。

<br>
###1-1. cs-login-aws
シェルスクリプトで定義された関数を実行する。

```sh:
function cs-login-aws() {
  version=$(echo $(aws --version 2>&1) | sed -e 's/aws-cli\/\([0-9]\{1,\}\).*/\1/')
  if [[ $version -eq 1 ]]; then
    $(aws ecr get-login --no-include-email --region ap-northeast-1)
  elif [[ "$version" -ge 2 ]]; then
    aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
  else
    echo "Error: could not detect aws command version."
    return 1
  fi
}
```

###変数の定義
変数を定義する際に`$`は不要。`=`でつなげば変数に代入になる。


###`$(コマンド)`
指定したコマンドを実行する。
バッククオートで囲んだ処理と同じ。


###`2>&1`
エラー内容も代入する。
標準エラー(2)出力を標準出力(&1)にリダイレクト(>)する。


###`$(aws --version 2>&1)`

```
$ aws --version
aws-cli/2.0.44 Python/3.7.4 Darwin/19.6.0 exe/x86_64
```

`2>&1`でエラーの場合もそのまま出力。


###`|`
パイプライン。前方の処理結果を後方のコマンドに渡す。

・`コマンド１ | コマンド２ | ,,,,`


###sed
指定のファイルや前から渡されたデータに対してコマンドを実行する。置換で使われることが多い。

・`sed [オプション] コマンド [ファイルパス]`

sedはStream EDitorの略。指定したファイルをコマンドに沿って処理する。

・`-e`
`--expression`。コマンドを追加する。


```:sコマンドによる置換。
sed 's/（置換前の文字パターン）/（置換後の文字パターン）/'
```

（参考）１文字ずつ変換させていく場合はsコマンドの代わりにyコマンドを使う。


###`\メタ文字` エスケープ
メタ文字（特殊記号）の前で\を使えばエスケープになる。

ディレクトリパスを表示する時などに使う。
`aaa\/bbb` -> `aaa/bbb`


###`\アルファベット` 定義済み正規表現（省略形）
\の後に指定のアルファベットを記述すると定義された正規表現となる。

アルファベットは、d, s, wの３文字（とその大文字）。

| 省略形 | 正規表現 | 内容 |
|:-:|:--|:--|
| \d  | [0-9]  | 数字  |
| \D  | [^0-9]  | 数字以外  |
| \s   | [ \f\n\r\t\v]  | 空白や改行 |
| \S  | [^ \f\n\r\t\v]   | 空白や改行以外  |
| \w  | [a-zA-Z0-9]  | アルフべットと数字  |
| \W  | [^a-zA-Z0-9]   | アルフべットと数字以外  |

- `[ ]`はいずれか１文字
- `[ ]`内のキャレット`^`は以外（not）
- `\f` 改ページ
- `\n` 改行（LF）
- `\r` 改行（CR）
- `\t` TAB
- `\v` 垂直タブ


###`| sed -e 's/aws-cli\/\([0-9]\{1,\}\).*/\1/'`
前方のコマンドで渡された結果に対し、パターン１をパターン２に置換。

- パターン１：`aws-cli\/\([0-9]\{1,\}\).*`
- パターン２：`\1`

**▼パターン１**
コマンドラインで使っているため\があるが、これを外すと本来の正規表現が見やすい。

`aws-cli/([0-9]{1,}).*`

「aws-cli/」の後に数字１文字以上の繰り返しが続き、その後に任意の文字が続く。

```:パターン１とマッチする文字列
aws-cli/2.0.44 Python/3.7.4 Darwin/19.6.0 exe/x86_64
```


<br>
**▼パターン２**
`\1`は前方の一つ目の`( )`の中身にするということ。

<br>
**▼sedの処理**

```
aws-cli/2.0.44 Python/3.7.4 Darwin/19.6.0 exe/x86_64
↓置換
2
```

`aws-cli/2`の2が抜き出される。


<br>
###ifの処理
・`if　条件 ;then 処理 fi` 
fiで終わるところが独特。必要に応じて分岐を使う。

- `elif 条件 ; then 処理`
- `else 処理`


```sh:
  if [[ $version -eq 1 ]]; then
    $(aws ecr get-login --no-include-email --region ap-northeast-1)
  elif [[ "$version" -ge 2 ]]; then
    aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
  else
    echo "Error: could not detect aws command version."
    return 1
  fi
```

###[[  ]]
真偽値を返すコマンドに、`test`, `[ ]`, `[[ ]]`がある。

`[ ]`は`test`のエイリアス。

`[[ ]]`は`[ ]`と似ているが、正規表現が使えたりより汎用性が高い。

**▼注意**
`[ 処理 ]`も`[[ 処理 ]]`どちらも処理の前後に**半角スペース必須**。


###-eq, -ge
testコマンド内の数値比較。
-eqはイコール。-geは以上。

| オプション | 意味 | 補足 |
|:-:|:--|:--|
| -eq  | 等しい  | Equal  |
| -le  | 以下  | Less than or Equal  |
| -ge  | 以上  | Greater than or Equal  |
| -lt  | 未満  | Less Than  |
| -gt  | より大きい | Greater Than |
| -ne  | 等しくない  | Not Equal  |

このオプションを使うとき対象は数値のみ。文字列だとエラーになる。

`-eq`は`=`でもOK。


**▼ターミナルで確認する方法**

・`$ コマンド; echo $?`

```
$ [[ 321 -eq  321 ]]; echo $?
0
```

・`$?`は前の処理結果が入っている。echoで処理結果を出力している。

| 出力 | 内容 |
|:-:|:-:|
| 0  | true  |
| 1  | false  |



###一つ目の条件分岐

```sh:
if [[ $version -eq 1 ]]; then
    $(aws ecr get-login --no-include-email --region ap-northeast-1)
```

変数`$version`の値が１ならthen以下の処理を実行。


###AWS CLIでECRレジストリにログイン

```
aws ecr get-login --region --no-include-email <region>
```

古いCLIを使った場合の方法。[AWS公式 get-login](https://docs.aws.amazon.com/cli/latest/reference/ecr/get-login.html)


<br>
###二つ目の条件分岐

```
elif [[ "$version" -ge 2 ]]; then
    aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
```

・`[[ "$version" -ge 2 ]]`
変数versionの値が２以上の場合はthen以下を実行。（awsのcliでECRレポジトリにログインするための処理がv1系とv2系で異なるため）

**▼mazonECRレジストリへの認証用PWの取得**

```
aws ecr get-login-password --region <region> 
```

**▼docker cli**
認証PWをdocker loginコマンドに渡す。

```
| docker login \
    --username AWS \
    --password-stdin <aws_account_id>.dkr.ecr.<region>.amazonaws.com
```

[AWS公式 get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html)



<br>
###三つ目の条件分岐

```
  else
    echo "Error: could not detect aws command version."
    return 1
```

`$version`が0または数値以外の場合はエラーメッセージを表示。

・`return 1`
エラー発生時の異常終了は慣例として1で終わる。


以上の処理で、dockerでawsのECRレポジトリにアクセスできるように設定完了。


```
docker pull 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/docker-base-images:php-fpm-grpc-f1
```

###1-2. docker pull
指定したイメージを取得する。

・`docker pull [OPTIONS] NAME[:TAG|@DIGEST]`
　┗ docker hub以外から取得する場合は、NAMEがレポジトリのURLになる。

- [OPTIONS]：　なし
- NAME：111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/docker-base-images
    - ECRのdocker-base-imageレポジトリ
- TAG: php-fpm-grpc-f1


ECRのレポジトリから指定したイメージ名（タグ名）のイメージを取得する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/8f609570-6faf-eeea-b03e-071045fd2392.png)




<br>
###1-3. docker tag
指定したイメージをコピーして新たなイメージ名（とタグ名）をつける。（リネームではなく新たなイメージができる）

・`docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]`

- SOURCE_IMAGE: 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/docker-base-images
- TAG: php-fpm-grpc-f1
- TARGET_IMAGE: cl_php-fpm-grpc
- TAG: f1

ECRから取得してきたイメージをローカルでリネーム。

```
REPOSITORY                                                             TAG                                        IMAGE ID       CREATED         SIZE
111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/docker-base-images   php-fpm-grpc-f1                       7d49fb079fb5   4 weeks ago     3.14GB
cl_php-fpm-grpc                                                  f1                                    7d49fb079fb5   4 weeks ago     3.14GB
```



<br>
##2. cs-login-aws
1-1. cs-login-awsの処理と同じ。
aws cliを使ってECRレポジトリのユーザー名とPWを取得し、dockerコマンドで接続できるようにしている。


<br>
##3. cs-envvars

```sh:cs-envvars
alias cs-envvars="GIT_HASH=\$(git rev-parse --short HEAD)"
```

・`GIT_HASH=`
環境変数GIT_HASHに値を代入している。

・`\$`
`エスケープして、`$`を文字列として表示

```
git rev-parse --short HEAD
```

最新のコミット番号(短縮版)を取得。

<br>
**▼実行例**

```:ターミナルでの実行例
$ SHA=$(git rev-parse --short HEAD)
$ echo $SHA
1784d4b
```



<br>
##3. docker-compose build php-fpm prd

・`docker-compose build [オプション] [サービス] [サービス],,,`

現在のディレクトリにある`docker-compose.yml`を参照し、指定したサービスの**イメージを作成**する


###php-fpm
php-fpmとは、FastCGI Process Managerの略で、PHPを動かすための機能。

NginxでPHPを起動する場合に必要となる。


<br>
**▼補足**
Nginxではphpを実行できないため。
Apachはデフォルトでphpを使える。




<br>
##docker-compose.yml
buildで参照されるdocker-composeファイルは以下のようになっている。

```yml:docker-compose.yml
version: '3'
services:
  php-fpm:
    build:
      context: ./
      dockerfile: docker/php-fpm/Dockerfile
      args:
        - PHP_BASE_IMAGE=cl_php-fpm-grpc:f1
    image: cs_php-fpm

   # Production
  prd:
    build:
      context: ./
      dockerfile: docker/production/Dockerfile
      args:
        - COMPOSE_PROJECT_NAME=cs
        - GIT_HASH=${GIT_HASH}
    image: cs:latest
    container_name: cs_prd
    tty: true
    ports:
      - 13004:80
    environment:
      - APP_ENV=production
      - APP_DEBUG=false

  # Staging
  stg:
    build:
      context: ./
      dockerfile: docker/production/Dockerfile
      args:
        - COMPOSE_PROJECT_NAME=cs
        - GIT_HASH=${GIT_HASH}
    image: cs:latest
    container_name: cs_stg
    tty: true
    ports:
      - 13003:80
    environment:
      - APP_ENV=staging
      - APP_DEBUG=true
    networks:
      - dev-network


  # MySQL Service
  db:
    image: mysql:5.7
    container_name: cs_mysql
    restart: unless-stopped
    tty: true
    environment:
      MYSQL_DATABASE: cs
      MYSQL_USER: cs
      MYSQL_PASSWORD: *****
      MYSQL_ROOT_PASSWORD: *****
      SERVICE_NAME: mysql
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    volumes:
      - dbdata:/var/lib/mysql
      - ./backup:/backup
    ports:
      - 3306:3306
    networks:
      - dev-network

  cache:
    image: memcached
    container_name: cs_memcached
    restart: unless-stopped
    tty: true
    ports:
      - '11211:11211'
    networks:
      - dev-network

# Docker Networks
networks:
  dev-network:
    driver: bridge

# Volumes
volumes:
  dbdata:
    driver: local
```

<br>
###php-fpmサービス

```yml:
  php-fpm:
    build:
      context: ./
      dockerfile: docker/php-fpm/Dockerfile
      args:
        - PHP_BASE_IMAGE=cl_php-fpm-grpc:f1
    image: cs_php-fpm
```

現在のディレクトリから見て、docker/php-fpm/Dockerfileのファイルでイメージを作成する。

####・`args: -Key=Value`
buildでイメージを作成する時に、指定したdockerfileにデータを渡せる。（`args: K:V`も使える）


####・`image: 名前`
作成したイメージに名前をつける。


<br>
###docker/php-fpm/Dockerfile

```Dockerfile
ARG PHP_BASE_IMAGE

FROM ${PHP_BASE_IMAGE}

RUN apt-get install -y libmemcached-dev \
    && pecl install memcached \
    && docker-php-ext-enable memcached

RUN docker-php-ext-install soap

# Cleanup dev packages
RUN apt-get autoremove -y \
    && rm -rf /var/cache/apt/*

RUN mkdir -p /app/
WORKDIR /app/
```

**▼概要**
AWSのECRレポジトリからダウンロード(pull)したイメージをベースに新たなイメージを作成する。

PHPの拡張モジュールである、分散型メモリキャッシュサーバーのmemcachedとAPI連携のためのsoapをインストールし有効化。

不要なパッケージを削除し軽量化。

Dockerのルートディレクトリを/app/に設定。


<br>
####・ARG 変数名
外部から渡された変数を受け取る。
docker-composeのargsで指定された同名の変数の値が入る。

`ARG 変数名=デフォルト値`
イコールでつなぐことで、デフォルト値を指定することもできる。


####・FROM ベースイメージ名
ベースイメージを指定する。
Dockerfileは冒頭にFROMが必須。（FROMで使うARGがある場合はその上に記述）


####・RUN <command>
指定したコマンドを実行する。

```
RUN apt-get install -y libmemcached-dev \
    && pecl install memcached \
    && docker-php-ext-enable memcached
```

PHPの拡張ライブラリであるmemchahedを有効化するための処理。

####・apt-get
Ubuntu（OSの一種）のパッケージ管理システム。

>macのhomebrew, windowsのwinget, JSのnpm, PHPのcomposer, Pythonのpip, Rubyのgem


```
apt-get install -y libmemcached-dev
```

・`-y`: すべてyes

**・libmemcached-dev**
memcachedサーバーの便利機能が入ったライブラリ（C、C++）。
PHPに**Memcachedをインストールするために必須**。


<br>

```
pecl install memcached 
```

・`pecl`
ピクルと読む。C言語で書かれたPHP用のライブラリのコマンド。
これでPHPの拡張モジュールをインストールできる。

ここでは`memcached`をインストール



####・memchached
分散メモリキャッシュサーバー。
メモリ上にデータを保存する（NoSQL）ことで、DBの負荷を減らし通信を高速化する。



####・docker-php-ext-enable
`docker-php-ext-enable 拡張モジュール名`

PHPの拡張モジュールをdockerで使えるようにする。


####・docker-php-ext-install
`docker-php-ext-install モジュール名`
指定したPHPの拡張モジュールをインストールする。


####・sorp
APIの実装に使う。
Single Object Access Protocolの略。通信プロトコルの一つ。

<br>

```
RUN apt-get autoremove -y \
    && rm -rf /var/cache/apt/*
```

不要なaptのパッケージを削除する。

####・`apt-get autoremove`
不要なパッケージを削除する（依存関係も含む）。


####・`rm [オプション] [対象]`
対象を削除する。

`-r`: ディレクトリ。これがないと対象はファイルのみ。
`-f`: 強制

####・/var/cache/apt/
aptの関連ファイルが保存されているディレクトリ。

・例：/var/cache/apt/archives/　
aptがインストールしたパッケージが保存される。



<br>

```
RUN mkdir -p /app/
WORKDIR /app/
```

####・mkdir -p パス
指定したパスにディレクトリを強制的に作成する。

`-p`は`--parent`オプション。
これがないと、ディレクトリが既にある場合や、そこのパスがない場合にエラーになる。

ルートディレクトリに`/app/`を作成。

####・WORKDIR パス
Dockerコンテナ内のルートディレクトリを指定。


<br>
##prdサービス

```yml:docker-compose.yml
  prd:
    build:
      context: ./
      dockerfile: docker/production/Dockerfile
      args:
        - COMPOSE_PROJECT_NAME=cs
        - GIT_HASH=${GIT_HASH}
    image: cs:latest
    container_name: cs_prd
    tty: true
    ports:
      - 13004:80
    environment:
      - APP_ENV=production
      - APP_DEBUG=false
```

docker/production/Dockerfileを使ってイメージを作成する。

変数で、`COMPOSE_PROJECT_NAME=cs`と`GIT_HASH=${GIT_HASH}`をDockerfileに渡す。

`${GIT_HASH}`は、cs-envvarsで定義されている。

```sh:cs-envvars
alias cs-envvars="GIT_HASH=\$(git rev-parse --short HEAD)"
```

作成したイメージに指定した名前を付与。
`docker-compose build`コマンドで実行するのはここまで。


**▼コンテナ起動時の処理（up or start）**
container_name, tty, ports, environmentはコンテナ起動時に使われる記述。


<br>
###Dockerfile

```:Dockerfile

ARG COMPOSE_PROJECT_NAME
FROM ${COMPOSE_PROJECT_NAME}_dev:latest AS builder

COPY .babelrc package.json package-lock.json webpack.mix.js ./
COPY resources ./resources

RUN npm install
RUN npm run production

FROM ${COMPOSE_PROJECT_NAME}_php-fpm:latest

RUN  mkdir -p storage/app/public \
    && mkdir -p storage/framework/sessions \
    && mkdir -p storage/framework/views \
    && mkdir -p storage/framework/cache

COPY composer.json composer.lock phpunit.xml server.php artisan ./
COPY bootstrap ./bootstrap
COPY tests ./tests
COPY config ./config
COPY database ./database
COPY app ./app
COPY public ./public
COPY resources ./resources
COPY routes ./routes
proto/generated/php
COPY cs-deploy/.env.production .env.production
COPY cs-deploy/.env.staging .env.staging
COPY cs-deploy/google-sheets-credentials.json ./storage/app/json/google-sheets-credentials.json

RUN /usr/bin/composer install --optimize-autoloader --no-dev

# TODO: remove
COPY storage ./storage

COPY --from=builder /app/public ./public

# RUN php artisan route:cache

#COPY php/php.overwrite.ini /usr/local/etc/php/conf.d/
COPY docker/php-fpm/php-fpm.conf /usr/local/etc/php-fpm.d/zz-docker.conf
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY docker/nginx/prod.conf /etc/nginx/sites-available/default

ARG GIT_HASH
RUN echo "${GIT_HASH}" > REVISION
ENV GIT_HASH=$GIT_HASH

RUN chown www-data:www-data -R /app

COPY docker/production/webserver.sh /docker/production/webserver.sh
RUN chmod +x /docker/production/webserver.sh

ENTRYPOINT ["/docker/production/webserver.sh"]
```


####・`ARG COMPOSE_PROJECT_NAME`
docker-composeのargsで渡されたデータを受け取る。

```yml:docker-compose.yml
      args:
        - COMPOSE_PROJECT_NAME=cs
        - GIT_HASH=${GIT_HASH}
```


####・マルチステージビルド
Dockerfileの中に複数のFROMがある処理をマルチステージビルドという。

指定したイメージをビルドステージとして構築し、必要なデータのみを次のイメージに渡すことで、最終的に作成するイメージを軽量化する。

`FROM イメージ名 AS ビルドステージ名`

ビルドステージ名を付けない場合は、FROMの順に0から数値が割り振られる。


####データ取得用のイメージを作成
FROM ${COMPOSE_PROJECT_NAME}_dev:latest AS builder

マルチステージビルドのビルドステージ。一部ディレクトリ（ここではpublic）のデータ取得のみが目的。


####・COPY
`COPY [フィル１] [ファイル２],,, [ディレクトリ名]`
指定したファイルを末尾に記述したディレクトリにコピーする。

```
COPY .babelrc package.json package-lock.json webpack.mix.js ./
```

**▼コピーするファイル**

| ファイル名 | 内容 |
|:-:|:--|
| .babelrc  | babelの設定が書かれたファイル  |
| package.json | JSのパッケージの依存関係  |
| package-lock.json  | インストールしたJSパッケージ  |
| webpack.mix.js  | Laravel Mix（コンパイラ）の設定ファイル  |


**▼移動先**
現在のディレクトリの配下に設置する。

`WORKDIR /app/`なので、その配下。

app
 ┗ .babelrc
 ┗ package.json

のようになる。



####・COPY resources ./resources
resourcesディレクトリを、/app/resourcesにコピーする。

**▼resourcesディレクトリ**
コンパイル前のビュー（.blade.php）や言語ファイル(lang)、sassが置いてあるファイル。


####`npm install`
package.jsonに記載されているパッケージをインストールする

####`npm run production`
production用のコンパイル後のファイルを作成する。

`npm run dev`と異なり、コンパイル後のファイルは改行などがない軽量版となる。

ファイルは`public`配下に出力される。
後ほど、このpublicのみを本番用のイメージにコピーする。


###セカンドステージ
２つ目のFROM。マルチステージビルドの2ndステージ。
このDockerfileで使われているFROMは２つなので、イメージ作成のベースイメージとなる。

`FROM ${COMPOSE_PROJECT_NAME}_php-fpm:latest`

指定しているイメージは、一つ前のサービスphp-fpmで作ったイメージ。タグ名の指定がない場合はlatestとなっている。

```yml:docker-compose.yml
  php-fpm:
    build:
      context: ./
      dockerfile: docker/php-fpm/Dockerfile
      args:
        - PHP_BASE_IMAGE=cl_php-fpm-grpc:f1
    image: cs_php-fpm
```


###mkdir
`-p`オプションを使って、指定したディレクトリを強制的に作成。

```:Dockerfile
RUN  mkdir -p storage/app/public \
    && mkdir -p storage/framework/sessions \
    && mkdir -p storage/framework/views \
    && mkdir -p storage/framework/cache
```

storageディレクトリを作っている。

**▼作成後のディレクトリ構造イメージ**
app
storage
　┗ app/public
　┗ framework
　　┗ sessions
　　┗ views
　　┗ chache



####COPY
ベースイメージからディレクトリ（ファイル）をコピー

```
COPY composer.json composer.lock phpunit.xml server.php artisan ./
COPY bootstrap ./bootstrap
COPY tests ./tests
COPY config ./config
COPY database ./database
COPY app ./app
COPY public ./public
COPY resources ./resources
COPY routes ./routes
COPY cs/.env.production .env.production
COPY cs/.env.staging .env.staging
COPY cs/google-sheets-credentials.json ./storage/app/json/google-sheets-credentials.json
```

Laravelで必要なファイルがこれでほとんど揃う。



####composerのインストール
PHPのパッケージ管理ソフトであるcomposerを本番環境としてインストールする。

```
RUN /usr/bin/composer install --optimize-autoloader --no-dev
```

・`–optimize-autoloader`オプション

PSR-0 / 4 オートローディングをクラスマップに変換して、オートローダーを高速化。本番環境での使用をお勧めしますが、実行に時間がかかるため、デフォルトでは実行しない

・`--no-dev`オプション
開発のみで必要なパッケージを記した、require-devをスキップ。

####COPY --from=ビルドステージ名
`COPY --from=builder /app/public ./public`

ステージビルドのASで指定した名前のステージから`app/public`ディレクトリをコピーする。



####confファイルのコピー

```
COPY docker/php-fpm/php-fpm.conf /usr/local/etc/php-fpm.d/zz-docker.conf
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY docker/nginx/prod.conf /etc/nginx/sites-available/default
```

nginxとphp-fpmのconfファイルをコピーする。



####GIT_HASH

```
ARG GIT_HASH 
RUN echo "${GIT_HASH}" > REVISION
ENV GIT_HASH=$GIT_HASH
```

・`ARG GIT_HASH`
docker-composeから渡された変数を受け取る。

・`RUN echo "${GIT_HASH}" > REVISION`
変数GIT_HASHをREVISIONに上書き。

`${変数}` :文字列として呼び出す
`>`　:上書き
`>>` :追記


####`ENV <key>=<value>`
環境変数にKVを設定する。

`ENV GIT_HASH=$GIT_HASH`
GIT_HASHというキーに、値`$GIT_HASH`を指定。


####`chown`
ファイルの所有者と所有グループを変更するコマンド。change owner（所有者）の略

・`chown [オプション] ユーザー[:グループ] ファイル`

`RUN chown www-data:www-data -R /app`
/app配下のディレクトリのユーザー権限、グループ権限をwww-dataにする。

- ユーザー www-data
- グループ　www-data
- `-R` 指定したディレクトリ配下も含める（再起的 recrusive）
- ディレクトリ/app



####・www-data
apacheを動かしているデフォルトのユーザー権限`www-data`。これに習い、Nginxおよびphp-fpmのユーザー名も`www-data`にしてある。

上記`chown`コマンドで、php-fpmとNginxがプロジェクトのルートディレクトリ配下にアクセスできるようになった。



####webserver.shのコピーと実行権限変更

```
COPY docker/production/webserver.sh /docker/production/webserver.sh
```

環境変数をコピペする処理が書かれたwebserver.shをdockerにコピーする。

```
RUN chmod +x /docker/production/webserver.sh
```

chmodコマンドはファイルの実行権限を返るコマンド。change modeの略。

+xで実行権限を与える。webserver.shに実行権限を付与。


####ENTRYPOINT
`ENTRYPOINT ["/docker/production/webserver.sh"]`

コンテナ起動時の処理。
webserver.shを実行する。



```sh:webserver.sh
#!/bin/bash

if [ "$APP_ENV" = "staging" ]; then
cp -f .env.staging .env
elif [ "$APP_ENV" = "production" ]; then
cp -f .env.production .env
fi

echo "APP_DEBUG=$APP_DEBUG" >> .env

cat .env

service nginx start
docker-php-entrypoint -F
```

`service nginx start`
Nginxを起動。


####docker-php-entrypoint
オプションを返すコマンド。
ここでは、オプションがある場合に、ENTRYPOINTに渡す。


```sh:docker-php-entrypoint
#!/bin/sh
set -e

# first arg is `-f` or `--some-option`
if [ "${1#-}" != "$1" ]; then
	set -- php "$@"
fi

exec "$@"
```

渡された引数がオプションかドかチェックし、オプションであればそれを値として返す。


・`set`コマンド
シェルの設定を確認するコマンド。

`-e`オプションはerrexitで、シェルの中で実行したコマンドで１つでもエラーが発生したらシェルを終了する。


・${1#-}
`$1`に格納された値に対するパターンマッチング。
`#`: 後ろに続く値を削除する
`#-`: -を削除する。　

例： -e > e

・`[ "${1#-}" != "$1" ]`
オプションが設定してある（-が含まれている）ならtrueになる。

・set -- 値
指定した値がオプションでないことを明示する。変数などが`-`で始まる場合に使う。


<br>
##コンテナの起動

```aliases.sh
alias cs-stg-up="cs-stg-build && docker-compose up stg"
```

コンテナの起動は`docker-compose up <サービス名>`を使う。

ファイルに変更があった場合にイメージのキャッシュを使わず、イメージを再ビルドしてから起動する。

###docker-compose up stg

```yml:docker-compose.yml
version: '3'
services:
  # Staging
  stg:
    build:
      context: ./
      dockerfile: docker/production/Dockerfile
      args:
        - COMPOSE_PROJECT_NAME=cs
        - GIT_HASH=${GIT_HASH}
    image: cs:latest
    container_name: cs
    tty: true
    ports:
      - 13003:80
    environment:
      - APP_ENV=staging
      - APP_DEBUG=true
    networks:
      - dev-network
 
#他サービスは省略
```

作成したイメージをベースにコンテナを起動する。
コンテナ起動時に実行される処理は以下。

```
    container_name: cs
    tty: true
    ports:
      - 13003:80
    environment:
      - APP_ENV=staging
      - APP_DEBUG=true
    networks:
      - dev-network
```

####container_name: コンテナ名
コンテナに名前をつける

####tty: true
コンテナを起動したままにする。

`docker exec -it <コンテナID_or_NAME> bash`でコンテナに接続するために必要。

####ports: ホスト側:コンテナ側
ホスト側のポートと、docker内でのポートを指定。

`ports -13003:80`
localhost:13003にアクセスすれば、コンテナ側の80番ポートにつながる。

####environment
環境変数の設定

#### networks
指定したネットワーク名にする。
デフォルトではdocker-composeに記載されているすべてのサービスが「ルートディレクトリ名_default」というネットワークに入る。

自分で設定することで、指定したサービスのみネットワーキングすることができる。