DockerをインストールしてLinux系コンテナを構築したときの備忘録

#目的

Dockerをインストールしていない状態から、Dockerをインストールしてコンテナ上のopenSUSEでzypperコマンドを使ってみる。
LPICとDocker学習を兼ねる。

#環境

macOS Catalina(バージョン10.15.7） MacBook Pro
Docker version 19.03.13

#Dockerインストール

[Docker公式](https://docs.docker.com/)の指示に従い、[Docker Hub](https://hub.docker.com/editions/community/docker-ce-desktop-mac/)からインストール。
インストール後にチュートリアルがあったので、DockerDesktopで指示どおりコマンドを入力（ボタンをクリックでもOK）。
内容としては、
①`alpine/git`というイメージから`repo`という名前のコンテナを構築し、コンテナ上にGitHubのリポジトリからクローンを作成する。
②コンテナにあるファイルたちをローカルにコピーする。
③Dockerfileからイメージを構築し、`docker101tutorial`という名前を付ける。
④その作成したイメージに`docker/docker101tutorial`という名前をつけ、DockerHubに上げて共有する。

```
$ docker run --name repo alpine/git clone https://github.com/docker/getting-started.git
$ docker cp repo:/git/getting-started/ .
$ cd getting-started/
$ docker build -t docker101tutorial .
$ docker tag docker101tutorial dockeridok/docker101tutorial 
$ docker push dockeridok/docker101tutorial

```

|コマンド等|説明|
|---|---|
|docker run [オプション] イメージ[:タグor@ダイジェスト値] [コマンド] [引数...]| 指定したイメージ上にコンテナ層を作成し、起動する。<br>docker create→docker startと同様の動作を行う。なお、指定したイメージがローカルにない場合はDocker Hubからダウンロードするのでdocker pullの動作を伴う場合もある。<br>今回は指定したイメージalpine/gitがローカルにないので、Docker Hubからダウンロードしている。|
|--name| コンテナに名前を付ける。今回はrepoという名前を付けている。デフォルトはランダムな文字列から名前をつけている。|
| clone|GitHubからクローンしている。ENTRYPOINTでgitを指定しているため、実質git cloneを実行している。|
|cp コンテナ：パス ローカルパス|コンテナのファイルシステム上にある内容を、ローカルのパスにコピーする。|
|docker build  [オプション] パス or URL or - |パスにあるDockerfileから新しいイメージを構築。|
| -t|`名前：タグ`形式で名前とオプションのタグを指定。今回は名前だけを指定し、タグを省略している。|
|docker tag [オプション] イメージ[:タグ] [レジストリのホスト/][ユーザ名/]名前[:タグ]|リポジトリ内のイメージにタグ付。今回は`docker101tutorial`というイメージに`dockeridok/docker101tutorial`という名前をつけている。|
|docker push [オプション] 名前[:タグ]|イメージをDocker Hubレジストリや、自分で作成したレジストリで共有できる。|

#Dockerfile

イメージのベースとなるDockerfile。
Dockerは、Dockerfileから命令を読み込んで、自動的にイメージを構築する。
今回は公式サイトチュートリアルに載っていた簡単なDockerfileを見本にし、Dockerへの理解を深める。

```:Dockerfile

# ベースとなるイメージ
FROM node:current-slim

# Dockerfileで指定したRUN,COPYなどの命令実行時の作業ディレクトリを指定
WORKDIR /usr/src/app

# ファイルをホストからコンテナ内にコピーする。
COPY package.json .

# イメージファイルシステム内でコマンドを実行する。
RUN npm install

# コンテナのポートを解放する。
EXPOSE 8080

# コンテナで指定されたコマンドを実行。CMDはコンテナ実行時のデフォルトを提供する。
CMD [ "npm", "start" ]

# 全てのファイルなどをコンテナ内にコピーする。
COPY . .

```



#openSUSEのイメージをインストールし、コンテナ上でコマンドを打てるようにする

Dockerのことが何となく分かってきたので、本題のopenSUSEコンテナを作成する。

openSUSEイメージの名称が[DockerHubのopensuse/leap](https://hub.docker.com/r/opensuse/leap)によりわかったので、あとは走らせるだけ。
コマンドを確認するだけなら仮想マシン構築より爆速。

```
% docker run -it opensuse/leap:latest
Unable to find image 'opensuse/leap:latest' locally
latest: Pulling from opensuse/leap
658f48177d00: Already exists 
Digest: sha256:
Status: Downloaded newer image for opensuse/leap:latest

0a5ec012802e:/ # cat /etc/*release
NAME="openSUSE Leap"
VERSION="15.2"
ID="opensuse-leap"
ID_LIKE="suse opensuse"
VERSION_ID="15.2"
PRETTY_NAME="openSUSE Leap 15.2"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:opensuse:leap:15.2"
BUG_REPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org/"

0a5ec012802e:/ # zypper --version
zypper 1.14.38
```

|コマンド等|説明|
|---|---|
|-i|コンテナの標準入力（STDIN）を取得。コンテナ内で標準入力ができるようになる。|
|-t| コンテナ内に擬似ターミナルを割り当てる。-tと合わせることで通常のターミナルのようにコマンド入力ができる（どこまで通常どおりに行えるか分からないが。）。|

#CentOSでsystemctl,localectlが使用できなかったので対処する

CentOSのコンテナも構築して使っていたが、`can't set the locale; make sure $LC_* and $LANG are correct`と表示されるのが煩わしかったのでlocaleを変更しようとしたら、

```
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to create bus connection: Host is down

```

と表示。
PID1をシェルが使用しているからsystemdが動けない？

```
[root@15900d9cd863 /]bash# ps
  PID TTY          TIME CMD
    1 pts/0    00:00:00 bash
  162 pts/0    00:00:00 ps

```

こちらの記事どおりにしたら解決しました。
百蔵の部屋[「CentOS7コンテナでsystemctlが使えない時」](
https://momozo.tech/2020/02/22/centos7%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%A7systemctl%E3%81%8C%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84%E6%99%82/)

```
docker run -itd --privileged イメージ /sbin/init

docker exec -it コンテナ /bin/bash

[root@d7a7f918cfde /]bash# ps
PID    TTY       TIME CMD
119    pts/1     00:00:00 bash
15560  pts/1     00:00:00 ps

```

|コマンド等|説明|
|---|---|
|--privileged| コンテナに対して拡張権限（全ての権限）を与える。他のコンテナにも接続でき、ホスト上の全てのデバイスに対して接続可能になる。|
| /sbin/init| systemdへのシンボリックリンクで、--privilegedと併用することで/sbin/initが動作してsystemctlなどが実行できるようになる|
|docker exec [オプション] コンテナ コマンド [引数...]|実行中のコンテナでコマンドを実行する。今回は、コンテナ内でコマンドを実行すると、「/bin/bash コマンド」という意味になる?|

ついでにlocale設定。設定後は`source /etc/locale.conf`で反映されるはず(`reboot`してコンテナから出てしまったので上記コマンドは行っていない。)。

```
[root@d7a7f918cfde /]bash# localectl
   System Locale: LANG=en_US.UTF-8
       VC Keymap: us
      X11 Layout: n/a
[root@d7a7f918cfde /]bash# localectl list-locales
C.utf8
[root@d7a7f918cfde /]bash# dnf -y install langpacks-ja
[root@d7a7f918cfde /]bash# localectl list-locales
C.utf8
ja_JP.eucjp
ja_JP.utf8
[root@d7a7f918cfde /]bash# localectl set-locale LANG=ja_JP.utf8
[root@d7a7f918cfde /]bash# localectl
   System Locale: LANG=ja_JP.utf8
       VC Keymap: us
      X11 Layout: n/a

```


#プロンプトの色付け

プロンプト部分を分かりやすくしたいので、色つけする。
参考サイト：とほほのWWW[「シェル入門」](http://www.tohoho-web.com/ex/shell.html#prompt)。

```
# シェル確認
$ echo $SHELL
# 設定ファイル編集。緑に色付けして時間も表示する。
$ vi /etc/bashrc
export PS1="\[\e[1;32m\][\u@\h \w][\t]\[\e[0m\]\s\ $"
#反映
$ source /etc/bashrc

```

#時間設定

プロンプトに時間を表示したら日本ではなかったので、日本に変更する。

```
[root@f95fa15cf5fb /][13:26:29]bash#timedatectl 
               Local time: 日 2020-11-01 13:26:37 UTC
           Universal time: 日 2020-11-01 13:26:37 UTC
                 RTC time: 日 2020-11-01 13:26:37
                Time zone: UTC (UTC, +0000)
System clock synchronized: no
              NTP service: n/a
          RTC in local TZ: no

[root@f95fa15cf5fb /][13:26:37]bash#timedatectl set-timezone Asia/Tokyo
       
[root@f95fa15cf5fb /][22:27:03]bash#timedatectl 
               Local time: 日 2020-11-01 22:27:07 JST
           Universal time: 日 2020-11-01 13:27:07 UTC
                 RTC time: 日 2020-11-01 13:27:07
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: no
              NTP service: n/a
          RTC in local TZ: no

```

　補完機能が有効にならないことが度々あって面倒だったので、有効にする。
　綺麗ではないが、以下のコマンド実行後にコンテナから抜け出し、コンテナをコミットしてイメージを作成し、そのイメージをコンテナにすることで補完機能を有効にした。


```
[root@f95fa15cf5fb /][22:32:18]bash#yum info bash-completion
Last metadata expiration check: 1:18:08 ago on 2020年11月01日 21時24分15秒.
Available Packages
Name         : bash-completion
Epoch        : 1
Version      : 2.7
Release      : 5.el8
Architecture : noarch
Size         : 274 k
Source       : bash-completion-2.7-5.el8.src.rpm
Repository   : BaseOS
Summary      : Programmable completion for Bash
URL          : https://github.com/scop/bash-completion
License      : GPLv2+
Description  : bash-completion is a collection of shell functions that take advantage
             : of the programmable completion feature of bash.

[root@f95fa15cf5fb /][22:42:23]bash#yum install bash-completion

```

#コンテナから脱出して同じ環境のコンテナに戻る

Ctrl+p,Ctrl+qでデタッチする（コンテナから出る。）。
コンテナは実行中。
コンテナに入るときは、前述のexecコマンドを入力して実行。

```
[root@fabcffc6d45e /][13:32:44]bash# read escape sequence

docker exec -it コンテナ /bin/bash
```

# 使用したDockerコマンドまとめ

```
# コンテナ削除
docker rm コンテナ名

# 実行中のコンテナを削除。--forceでコンテナを停止してから削除している。
docker rm --force コンテナ名

# 実行中だけでなく停止中のコンテナも確認
docker ps -a

# イメージ削除
docker rmi イメージ名

# イメージ全削除。-qオプションはIDのみ表示するので、引数として全イメージIDを渡している。
docker rmi `docker images -q`

# 全てのイメージ確認
docker images

# コンテナ起動。公式サイトのチュートリアルより。コマンドの詳細は後述。
docker run --publish 8000:8080 --detach --name bb bulletinboard:1.0

# 停止したコンテナを起動
docker start コンテナID or 名前

# systemdなどを動かす時のコンテナ起動
docker run -itd --privileged イメージID /sbin/init
docker exec -it コンテナID or 名前 /bin/bash

# 何らかの原因で上記コンテナが停止した時の起動法
docker start コンテナID or 名前
docker exec -it コンテナID or 名前 /bin/bash

# コンテナを起動したままコンテナから抜け出す
Ctrl+P,Ctrl+Qでデタッチしてコンテナから抜け出す

# コンテナからイメージを作成
docker commit -m "message" -a ”担当者" \
コンテナID  hogeuser/opensuse:v2
```

|コマンド等|説明|
|---|---|
|--publish 8000:8080|コンテナのポートをホスト側に公開。ホストポート8000をコンテナポート8080に転送する。
| --detach| コンテナをバックグラウンドで実行。|
|docker commit [オプション] コンテナ [リポジトリ[:タグ]] |コンテナのファイル変更や設定を反映した新しいイメージを作成する。|