Dockerイメージを小さくするため一時ファイルはCOPYではなくローカルサーバーから取得する

ロケールとタイムゾーンを変更し、フィーチャーを追加したLibertyイメージをオフライン環境でビルドする必要があり、イメージサイズを小さくするため、一時的に必要なファイルについて、`COPY`コマンドではなくローカルサーバーから取得するようにしてみたメモ。

前提としてもともとイメージに`wget`等が入っている必要があり、ない場合は一時的に入れることもできるが、使える状況は限られるかもしれない。

## オンライン環境でのイメージのビルド

普通にオンライン環境でビルドするとしたら次のようになる。

```dockerfile:Dockerfile
FROM websphere-liberty:18.0.0.4-javaee8
USER 0
RUN apt-get update \
  && DEBIAN_FRONTEND=noninteractive apt-get install -y \
    language-pack-ja \
    tzdata \
  && rm -rf /var/lib/apt/lists/* \
  && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  && dpkg-reconfigure -f noninteractive tzdata
USER 1001
RUN /opt/ibm/wlp/bin/installUtility install wmqJmsClient-2.0 --acceptLicense
ENV LANG ja_JP.UTF-8
ENV TZ Asia/Tokyo
```

```shell
docker build -t liberty-test:online .
```

## オフライン環境でのイメージのビルド

### オフラインでのビルドに必要なファイルの取得

ビルドに必要なファイルを取得するため、オンライン環境で、`-u`でrootユーザーを指定し、カレントディレクトリーをマウントしてLibertyコンテナを起動して中に入る。

```shell
docker run --rm -it -u 0 -v $PWD:/work websphere-liberty:18.0.0.4-javaee8 bash
```

必要なUbuntuのパッケージをダウンロードオンリーモードで取得する。

```shell
apt-get update
apt-get install -y -d language-pack-ja
apt-get install -y -d tzdata
```

`/var/cache/apt/archives`にダウンロードしたファイルがあるので、マウントしたディレクトリーにコピーする。

```shell
cp /var/cache/apt/archives/*.deb /work
```

Libertyフィーチャーをダウンロードする。

```shell
mkdir /tmp/wmqJmsClient-2.0
/opt/ibm/wlp/bin/installUtility download wmqJmsClient-2.0 --location=/tmp/wmqJmsClient-2.0
```

ダウンロードしたファイルを、マウントしたディレクトリーにアーカイブして保存する。

```shell
cd /tmp
tar czvf /work/wmqJmsClient-2.0.tar.gz wmqJmsClient-2.0
```

コンテナを`exit`する。

### オフライン環境でCOPYを使ってビルド

`COPY`命令を使う場合は以下のようになる。

```dockerfile:Dockerfile
FROM websphere-liberty:18.0.0.4-javaee8
USER 0
COPY *.deb /tmp/
RUN DEBIAN_FRONTEND=noninteractive dpkg -i \
    /tmp/language-pack-ja-base_1%3a16.04+20160627_all.deb \
    /tmp/language-pack-ja_1%3a16.04+20171210_all.deb \
    /tmp/locales_2.23-0ubuntu10_all.deb \
    /tmp/tzdata_2018i-0ubuntu0.16.04_all.deb \
  && rm -rf /tmp/* \
  && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  && dpkg-reconfigure -f noninteractive tzdata
USER 1001
COPY --chown=1001:0 wmqJmsClient-2.0.tar.gz /tmp/
RUN tar xzvf /tmp/wmqJmsClient-2.0.tar.gz -C /tmp \
  && /opt/ibm/wlp/bin/installUtility install wmqJmsClient-2.0 \
    --acceptLicense --from=/tmp/wmqJmsClient-2.0 \
  && rm -rf /tmp/*
ENV LANG ja_JP.UTF-8
ENV TZ Asia/Tokyo
```

```
.
├── Dockerfile
├── language-pack-ja-base_1%3a16.04+20160627_all.deb
├── language-pack-ja_1%3a16.04+20171210_all.deb
├── locales_2.23-0ubuntu10_all.deb
├── tzdata_2018i-0ubuntu0.16.04_all.deb
└── wmqJmsClient-2.0.tar.gz
```

```shell
docker build -t liberty-test:offline-copy .
```

COPYした時点でレイヤーができているため、一時ファイルを削除したとしてもイメージサイズが増えている。

```shell-session
$ docker images | grep liberty-test
liberty-test                          offline-copy           39df53382b2e        3 seconds ago       630MB
liberty-test                          online                 5040739eb1d2        24 seconds ago      611MB
$
```

### オフライン環境でローカルサーバーを使ってビルド

pythonを使ってローカルで簡易Webサーバーを起動する。カレントディレクトリが公開されるので公開したいファイルがあるディレクトリで実行する。

```shell:Python3の場合
python3 -m http.server
```

```shell:Python2の場合
python -m SimpleHTTPServer
```

ポート番号を指定したい場合は`python3 -m http.server 8888`のように指定できる。

Webサーバーを起動すると以下のようにHTTPサーバー経由でアクセスできる。

<img width="506" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/86449/26b40a03-1e23-fc98-ccc6-b8952598db6f.png">

このサーバーを使い`wget`で一時ファイルを取得し、一時ファイルを削除するところまでを一つの`RUN`コマンドに書く。

注意点として、`localhost`ではビルド時にアクセスできないため、Webサーバーを起動しているマシンの実IPを指定する必要がある。

また、ローカルにあるファイル名と、Webサーバーに公開したときのURLと、`wget`でsaveしたときのファイル名がURLエンコードされたりデコードされたりでちょっとずつ変わってくるので注意が必要。

```dockerfile:Dockerfile
FROM websphere-liberty:18.0.0.4-javaee8
USER 0
RUN wget -P /tmp http://9.237.53.92:8000/language-pack-ja-base_1%253a16.04%2B20160627_all.deb \
  && wget -P /tmp http://9.237.53.92:8000/language-pack-ja_1%253a16.04%2B20171210_all.deb \
  && wget -P /tmp http://9.237.53.92:8000/locales_2.23-0ubuntu10_all.deb \
  && wget -P /tmp http://9.237.53.92:8000/tzdata_2018i-0ubuntu0.16.04_all.deb \
  && DEBIAN_FRONTEND=noninteractive dpkg -i \
    /tmp/language-pack-ja-base_1:16.04+20160627_all.deb \
    /tmp/language-pack-ja_1:16.04+20171210_all.deb \
    /tmp/locales_2.23-0ubuntu10_all.deb \
    /tmp/tzdata_2018i-0ubuntu0.16.04_all.deb \
  && rm -rf /tmp/* \
  && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  && dpkg-reconfigure -f noninteractive tzdata
USER 1001
RUN wget -P /tmp http://9.237.53.92:8000/wmqJmsClient-2.0.tar.gz \
  && tar xzvf /tmp/wmqJmsClient-2.0.tar.gz -C /tmp \
  && /opt/ibm/wlp/bin/installUtility install wmqJmsClient-2.0 \
    --acceptLicense --from=/tmp/wmqJmsClient-2.0 \
  && rm -rf /tmp/*
ENV LANG ja_JP.UTF-8
ENV TZ Asia/Tokyo
```

```shell
docker build -t liberty-test:offline-local-server .
```

イメージサイズを比較してみる。オンラインでビルドしたときと同じサイズになった。

```
$ docker images | grep liberty-test
liberty-test                          offline-local-server   aa609cfad56f        4 seconds ago        611MB
liberty-test                          offline-copy           39df53382b2e        About a minute ago   630MB
liberty-test                          online                 5040739eb1d2        About a minute ago   611MB
$ 
```

ビルド手順が複雑で`Dockerfile`もわかりにくいものになってしまうため、わざわざここまですることはあまりなさそう。

## 参考リンク

- [Macで簡易ローカルサーバーをたてる](https://qiita.com/0084ken/items/27ffb19fcc4d81d6bbbb)
- [What is the Python 3 equivalent of “python -m SimpleHTTPServer”](https://stackoverflow.com/questions/7943751/what-is-the-python-3-equivalent-of-python-m-simplehttpserver)
- [Libertyコンテナにロケールとタイムゾーンを設定する](https://qiita.com/sotoiwa/items/3c85c9946e5ea7cab3a7)