④１日１０分で理解するコンテナ技術入門 - リモートレジストリの利用とサービスの公開 -

[前回](https://qiita.com/goroneko/items/8024bee8e8f58da49101)はシンプルなウェブアプリケーションをDockerを使って動かしてみました。今回は、リモートレジストリとCaaSを使って、前回ローカルで動かしたアプリケーションをインターネット上に公開してみたいと思います。

# コンテナイメージの編集
前回はコンテナ同士の通信にコンテナ名を用いましたが、今回利用するOCIのCaaSではコンテナ名による通信ができないので少しコードを変更します。
```python:app.py
# データベースの初期化
def init_db():
    conn = mysql.connector.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='password',
        database='flask_app'
    )
    cursor = conn.cursor()
    cursor.execute('CREATE TABLE IF NOT EXISTS articles (id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255), content TEXT)')
    conn.commit()
    cursor.close()
    conn.close()

init_db()

def get_db_connection():
    conn = mysql.connector.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='password',
        database='flask_app'
    )
    return conn
```
`app.py`のDB関係の部分のコードにおいて、`host`を`mysql`から`127.0.0.1`に変更しておきます。
変更したら、以下のコマンドでビルドします。
```bash
docker build -t simple-knowledge-sharing-platform .
```

# リモートレジストリの利用
コンテナ化したアプリケーションをCaaS (Container as a Service)をつかって公開するべく、まずはリモートレジストリにイメージをプッシュします。本稿ではOCIを利用するのでOCIのコンテナレジストリサービスとCaaSを利用しますが、基本的な手順はどのクラウドベンダーでも同様です。また、Docker Hubのようなレジストリサービスを利用して、インスタンスだけクラウドベンダーのものを利用するといったことも可能です。

## リモートレポジトリの作成
まずはリモートレジストリサービス側で、レポジトリを作成します。OCIにおいては、ホーム画面左上のハンバーガーメニューから、下記画像のような手順でレジストリサービスにアクセスできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/044299bd-a469-bf2b-0a49-a196038b610d.png)
レポジトリの作成をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/b845ff64-5353-c746-882d-27ac57e9dc4d.png)
ご自身のコンパートメントが選択されていることを確認して、アクセスをパブリックにし、任意のリポジトリ名を入力して作成します。なお、リポジトリ名はテナンシ内で重複できないので注意してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/435149bc-6bb1-308e-7254-8ac2112d4495.png)
作成すると、以下のようにリポジトリの詳細が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/9a4638d9-e35d-8e53-e4a0-ef98f3b9a1b6.png)

## リモートレポジトリへ接続するための準備
リモートレポジトリへ接続する際、ユーザー名とパスワードを聞かれます。ユーザー名はリポジトリの詳細にあるユーザーから確認できます。パスワードは、OCIでは認証トークンを用います。
認証トークンは、以下の手順で取得できます。
右上のアイコンをクリックし、出てくるメニューからユーザー名をクリックします。そうすると、以下のような画面に遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/432806c9-795b-918a-e138-b91d33873aa4.png)
この画面を下へスクロールすると、左に認証トークンというメニューがあるのでクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/56fc4682-032e-9685-856b-c56f7dabd347.png)
トークンの生成をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/f8b00dc2-ace0-6f16-02a9-fa70eeffe850.png)
適当な説明を入力し、作成ボタンを押すと、以下のように認証トークンが取得できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/c1e2d443-0540-806c-635c-e1c022048dcf.png)
このトークンをメモ帳などにコピーしておきます。
また、トークンの画面を閉じた後、テナンシのネームスペースを画面上のユーザー情報からメモ帳などにコピーしておきます。

## リモートレジストリへログイン
ここからは、`docker`コマンドを使ってリモートレジストリへログインします。作成したリポジトリのリージョンコードを[ここ](https://docs.oracle.com/ja-jp/iaas/Content/General/Concepts/regions.htm)から調べます。私はトロントに作成したので、`yyz`になります。
下記のコマンドでリモートレジストリにログインします。
```bash
$ docker login yyz.ocir.io
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
Username: <テナンシのネームスペース>/<リポジトリの詳細画面に表示されている、ユーザー名>
Password: <作成した認証トークンを入力>
Login Succeeded!
```
以上で接続準備は完了です。

## リモートリポジトリにイメージをプッシュ
次に、前回作成したコンテナイメージをリモートリポジトリにプッシュします。まずは、前回作成したイメージを`docker image ls`コマンドで確認します。
```
$ docker image ls
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
REPOSITORY                                   TAG         IMAGE ID      CREATED        SIZE
localhost/simple-knowledge-sharing-platform  latest      7ddb674174a7  5 seconds ago  238 MB
docker.io/library/mysql                      8.0         1eba4c9bcaa8  6 weeks ago    583 MB
docker.io/library/python                     3.9-slim    4602238ffbdc  2 months ago   131 MB
```
この中で、カスタムイメージは`localhost/simple-knowledge-sharing-platform`だけなので、これをプッシュします（カスタムではないイメージは、CaaS側で公式レポジトリから取得できるため）。
dockerイメージは、`REPOSITORY名` + `TAG`で識別します。`REPOSITORY名`は通常、`コンテナレジストリのドメイン` + `そのコンテナレジストリで作ったレポジトリ名`になります。`TAG`は、同じレポジトリ内でイメージを区別するための識別子で、バージョン管理などに使われます。
これを整理すると以下のようになります。
|  | 用途 | 今回の場合 |
| --- | --- | --- |
| レジストリのドメイン | イメージが保存されているレジストリの場所を示す | yyz.ocir.io |
| レポジトリ名 | レジストリ内の特定のプロジェクトやアプリケーションを識別する | simple-knowledge-sharing-platform |
| REPOSITORY | イメージのグループ名で、同じソフトウェアの異なるバージョンを管理する | yyz.ocir.io/テナンシのネームスペース/simple-knowledge-sharing-platform |
| TAG | リポジトリ内の特定のイメージバージョンを識別する | latest |

上の表を参考にしながら、実際にカスタムイメージをプッシュします。カスタムイメージは`localhost/simple-knowledge-sharing-platform`ですが、このままではプッシュできません。それは、レジストリのドメインが今回利用するOCIのレジストリと異なるからです。なので、まずはレジストリのドメインを変更する必要があります。変更は、以下のコマンドで行います。
```bash
$ docker tag localhost/simple-knowledge-sharing-platform yyz.ocir.io/<テナンシのネームスペース>/simple-knowledge-sharing-platform:latest
```
私のテナンシのネームスペースは`orasejapan`なので、以下のようになります。
```bash
$ docker tag localhost/simple-knowledge-sharing-platform yyz.ocir.io/orasejapan/simple-knowledge-sharing-platform:latest
```
ここでもう一度`docker image ls`を実行すると、イメージ一覧に今入力したものが増えています。
```
$ docker image ls
REPOSITORY                                                TAG         IMAGE ID      CREATED       SIZE
localhost/simple-knowledge-sharing-platform               latest      7ddb674174a7  18 hours ago  238 MB
yyz.ocir.io/orasejapan/simple-knowledge-sharing-platform  latest      7ddb674174a7  18 hours ago  238 MB
docker.io/library/mysql                                   8.0         1eba4c9bcaa8  6 weeks ago   583 MB
docker.io/library/python                                  3.9-slim    4602238ffbdc  2 months ago  131 MB
```
`docker push`コマンドを使ってリモートレジストリにイメージをプッシュします。
```
docker push yyz.ocir.io/orasejapan/simple-knowledge-sharing-platform:latest
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
Getting image source signatures
Copying blob 205262265e50 done
Copying blob 146826fa3ca0 done
Copying blob 5d4427064ecc done
Copying blob ae96698df02c done
Copying blob e555c0055a9b done
Copying blob fd8c1935b82d done
Copying blob 53af208dc77a done
Copying blob 3561557866f1 done
Copying blob 1b3e866d3731 done
Copying blob 26caac8dde11 done
Copying blob 60298db5d2d2 done
Copying blob ce168d0041d5 done
Copying blob e31afd319957 done
Copying config 7ddb674174 done
Writing manifest to image destination
```
以上で、カスタムのコンテナイメージをリモートレジストリにあげることができました。

# CaaSの利用
## Container Instanceの作成
OCIでは、Container InstanceというCaaSがあるので、それを利用します。画面左上のハンバーガーメニューから、コンテナインスタンスを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/7f073d60-a54c-1d6c-3b43-1fe20dcba63e.png)
Create Container Instanceをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/dfe73c8b-449e-fbdf-5172-4663f42343c3.png)
コンテナインスタンス作成の画面が表示されます。この画面で入力するのは、
1. コンテナインスタンスの名前
1. コンテナインスタンスを作成するネットワーク（Networking）

の2つです。コンテナインスタンスの名前はお好きなものを入力してください。Networkingは、Create new virtual cloud networkを選択してください。他はデフォルトで大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/09a768d6-edb6-927e-5165-85499a8b7e5f.png)
次をクリックします。
Select Imageをクリックし、先ほどプッシュしたイメージを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/9f674ca2-8def-5a14-807e-bb9b42785e7f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/985e6ca8-76af-f9df-a58a-a03b61f44d8b.png)
Another ContainerボタンをクリックしてMySQLのコンテナを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/c8bf178c-dfe0-c69e-ea31-e4074ba6aadf.png)
nameにmysqlを入力して、Select Imageをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/aefede0e-ede2-f5f0-5f3a-02f5f70d9d7a.png)
下の画像のように選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/14474dea-2c98-94ef-6b3f-8ec17918748a.png)
下の画像のように環境変数を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/511ddaa1-dfee-4a1c-81c7-e6604e2d0f2a.png)
次を押した後、Createを押して作成します。
作成が完了すると、以下のような画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/497dc639-1e3e-e146-003d-189bb1fbd525.png)

## ネットワークの設定
今回のウェブアプリでは、5000ポートで待ち受けています。そのため、コンテナインスタンス作成時に作成したネットワークのファイアウォールに、5000番を許可するルールを追加します。
左上のハンバーガーメニューから、仮想・クラウドネットワークを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/0ba71693-d9b0-3bac-6686-391c13615af3.png)
作成したネットワーク名を選択し、詳細画面に入ります。
画面を下にスクロールして、セキュリティ・リストをクリックして、Default Security List for xxxをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/3c05a5fc-3c61-03dd-8c51-f416c5db634a.png)
イングレスルールの追加をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/e9b4790a-a335-e7a1-9a84-b7a1e58dfcb7.png)
下記のように設定して、5000番ポートへのアクセスを受け付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/5c7cab37-da89-4835-d872-e6d3b0c77a63.png)
以上でネットワークの設定は終了です。

## アプリケーションが公開されているかを確認
コンテナインスタンスのパブリックIPアドレスを確認して、実際にウェブアプリケーションにインターネットからアクセスしてみましょう。
もういちどコンテナインスタンスの詳細画面を開きます。
下記画像の位置にパブリックIPアドレスが書いてあるので確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/b3082f74-ee84-4b22-0694-fe1de49ad8df.png)
私の環境では、`192.18.146.40`となっているので、ブラウザに入力するのは`192.18.146.40:5000`になります。
アクセスすると以下のように無事接続できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/3404c9ce-a286-14ea-8a00-e2286c32737c.png)

# まとめ
今回はリモートレジストリの利用と、CaaSを使ったアプリケーションの公開を行いました。[次回](https://qiita.com/goroneko/items/48b7036d10a0d6548114)はここまでのまとめと、仮想マシンとの違いについて説明したいと思います。