AWS ECS Fargate から OCI OKE への移行ガイド

# 1. AWS ECS Fargate から OCI OKE への移行ガイド

## 1.1. はじめに

この記事は、AWS ECS Fargateで稼働しているアプリケーションを Oracle Cloud Infrastructure (OCI) Container Engine for Kubernetes (OKE) へ移行するプロセスについて説明します。前半ではAWS側の環境準備と ECS Fargateへのサンプル・アプリケーションのデプロイの流れを説明し、後半では同サンプル・アプリケーションをOCI OKEへデプロイする流れを説明します。

**AWS ECS Fargateの構成図：**

![arch-fargate-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/82d9f1a0-2911-4971-9471-2c61876caedb.png)

**OCI OKEの構成図：**

![arch-oke-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/0d9d0171-b4f4-2588-db84-6d21a7d16676.png)


「Hello World!」のコンテンツと表示する単純なApache2アプリケーションを利用しています。データベースやストレージなどは使用していません。インタネットからアクセスできるように、コンテナ上公開されたポートはロードバランサーを経由して公開し、さらに、DNSレコードを追加し、自分のドメインからサンプル・アプリケーションへRedirectします。

Oracle Cloud Infrastructure Container Engine for Kubernetesは、完全に管理されたスケーラブルで可用性の高いサービスで、コンテナ化されたアプリケーションをクラウドにデプロイする際に使用できます。詳細は、[OCI OKE ドキュメント](https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Concepts/contengoverview.htm)を参照してください。

## 1.2. 前提条件

AWS および Oracle Cloud Infrastructureテナンシへのアクセス権が必要です。各リソースを作成および/または管理するには、次のいずれかに属している必要があります:

- テナンシの管理者グループ
- ポリシーが適切な権限を付与するグループ

## 1.3. ローカル開発環境の準備

ローカル開発環境は、主に、次の目的として利用されます。
- コンテナー・イメージの作成
- aws-cliの実行
- oci-cliの実行
- kubectlの実行

この記事では、ローカル開発環境は、Oracle Linux 8を利用しています。ほかのOSをご利用の場合、ご利用のOSに応じて適当に手順を読み替えてください。

### 1.3.1. Podmanのインストール

コンテナー・イメージを作成するため、ローカル開発環境にコンテナー実行環境が必要です。この記事では、Podmanを利用します。ほかのコンテナー実行環境を利用している場合、適当にガイドを変更してください。

Podmanは、Red Hat社を中心とするコミュニティが開発している、Docker互換のコンテナエンジンです。RHEL、CentOS、Fedora などの Linuxディストリビューションに標準で付属しています。

Podmanがインストールされていない場合、[Podmanドキュメント](https://podman.io/docs/installation)を参照してPodmanをインストールします。

インストールが完了したら、次のコマンドを実行して確認します。

```bash
[opc@containerdemo ~]$ docker --version
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
podman version 4.6.1
```

## 1.4. AWS ECS Fargateにアプリケーションをデプロイする

### 1.4.1. AWS CLI のインストール

[AWS ドキュメント](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)を参照して、ローカル開発環境にAWS CLIをインストールします。

インストールが完了したら、次のコマンドを実行して確認します。

```bash
[opc@containerdemo ~]$ aws --version
aws-cli/2.15.9 Python/3.11.6 Linux/5.15.0-100.96.32.el8uek.x86_64 exe/x86_64.oracle.8 prompt/off
```

### 1.4.2. AWS IAM ユーザーの作成

AWS CLIを設定する前に、先にIAMユーザーの作成が必要です。IAMユーザーが未作成の場合は、「IAM ユーザーガイド」の「[IAM ユーザーの作成 (コンソール)](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_users_create.html#id_users_create_console)」の手順に従ってIAMユーザーを作成します。

`許可のオプション` で、このユーザーにアクセス許可を割り当てる方法として `ポリシーを直接アタッチする`を選択します。簡単のために、このユーザーにアタッチする `AdministratorAccess` ポリシーを選択します。

### 1.4.3. AWS IAM ユーザーのアクセスキーの取得

1. AWS IAMユーザーの詳細ページで、`セキュリティ認証情報`ページを選択します。次に、`アクセスキー`で `アクセスキーの作成` を選択します。

2. `アクセスキーの作成ステップ 1`で、`コマンドラインインターフェイス (CLI)` を選択します。

3. `アクセスキーの作成ステップ 2` で、オプションのタグを入力して `次へ` を選択します。

4. `アクセスキーの作成ステップ 3` で、`.csv ファイルをダウンロード`を選択し、IAM ユーザーのアクセスキーとシークレットアクセスキーを含む `.csv` ファイルを保存します。この情報は後で必要になります。

5. `完了` を選択します。

### 1.4.4. AWS CLI の設定

1. AWS CLI を設定する次のコマンドを実行します。

    ```bash
    [opc@containerdemo hello-world]$ aws configure
    AWS Access Key ID [None]: IAM ユーザーのアクセスキー
    AWS Secret Access Key [None]: IAM ユーザーのシークレットアクセスキー
    Default region name [None]: ap-northeast-1
    Default output format [None]: json
    ```

    > AWS リージョンと出力形式は必要に応じて変更してください。

2. AWS CLIを確認します。
    
    ```bash
    [opc@containerdemo ~]$ aws s3 ls
    2023-01-05 07:07:45 aws-cloudtrail-logs-281288470701-7f0f8f9e
    ```

### 1.4.5. Amazon ECS で使用するコンテナイメージの作成

参考資料：

[Amazon ECS で使用するコンテナイメージの作成](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/create-container-image.html)


1. Dockerfile という名前のファイルを作成します。

    `touch Dockerfile`

2. 前の手順で作成した Dockerfile を編集し、以下のコンテンツを追加します。
    
    ```dockerfile
    FROM ubuntu:18.04
    
    # Install dependencies
    RUN apt-get update && \
        apt-get -y install apache2
    
    # Install apache and write hello world message
    RUN echo 'Hello World!' > /var/www/html/index.html
    
    # Configure apache
    RUN echo '. /etc/apache2/envvars' > /root/run_apache.sh && \
        echo 'mkdir -p /var/run/apache2' >> /root/run_apache.sh && \
        echo 'mkdir -p /var/lock/apache2' >> /root/run_apache.sh && \ 
        echo '/usr/sbin/apache2 -D FOREGROUND' >> /root/run_apache.sh && \ 
        chmod 755 /root/run_apache.sh
    
    EXPOSE 80
    
    CMD /root/run_apache.sh
    ```

    > この Dockerfile は Ubuntu 18.04 イメージを使用します。RUN の手順により、パッケージキャッシュが更新され、ウェブ サーバー用のいくつかのソフトウェアがインストールされてから、「Hello World!」 のコンテンツがウェブサーバーのドキュメントルートに書き込みされます。EXPOSE の命令はコンテナ上のポート 80 を公開し、CMD の命令はウェブサーバーを起動します。

3. Dockerfile から Docker イメージを作成します。

    `docker build -t hello-world .`

4. 新しく構築されたイメージを実行します。`-p 8080:80` オプションは、コンテナ上の公開されたポート `80` をホストシステム上のポート `8080` にマッピングします。

    `docker run -dp 8080:80 hello-world`

5. コンテナーが起動したことを確認します。

    ```bash
    [opc@containerdemo ~]$ docker ps
    Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
    CONTAINER ID  IMAGE                         COMMAND               CREATED        STATUS        PORTS                 NAMES
    459e1e65afe2  localhost/hello-world:latest  /bin/sh -c /root/...  7 seconds ago  Up 8 seconds  0.0.0.0:8080->80/tcp  affectionate_gates
    ```

6. Dockerを実行している、コンテナのホストサーバーを参照します。「Hello, World!」が確認できます。これでコンテナー・イメージの作成が完了です。

    ```bash
    [opc@containerdemo ~]$ curl localhost:8080
    Hello World!
    ```
    
### 1.4.6. Amazon Elastic Container Registry にイメージをプッシュする

Amazon ECR はマネージド型 AWS Docker レジストリサービスです。Docker CLI を使用して、Amazon ECR リポジトリ内のイメージをプッシュ、プル、および管理できます。

1. hello-world イメージを保存する Amazon ECR リポジトリを作成します。region を、AWS リージョン に置き換えます (例えば ap-northeast-1)。

    `aws ecr create-repository --repository-name hello-repository --region <region>`

    出力:
    ```json
    {
        "repository": {
            "registryId": "aws_account_id",
            "repositoryName": "hello-repository",
            "repositoryArn": "arn:aws:ecr:region:aws_account_id:repository/hello-repository",
            "createdAt": 1505337806.0,
            "repositoryUri": "aws_account_id.dkr.ecr.region.amazonaws.com/hello-repository"
        }
    }
    ```

1. 前のステップの `repositoryUri` の値で hello-world イメージにタグを付けます。

    `docker tag hello-world <aws_account_id>.dkr.ecr.<region>.amazonaws.com/hello-repository`

    イメージタグを省略した場合、タグは latest と見なされます。イメージタグを指定する場合、次の様に設定します。
    
    `docker tag hello-world <aws_account_id>.dkr.ecr.<region>.amazonaws.com/hello-repository:tag`

1. `aws ecr get-login-password` コマンドを実行します。認証先のレジストリ URI を指定します。

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

    出力:
    
    `Login Succeeded`

1. 前のステップのrepositoryUri値を使用して、Amazon ECR にイメージをプッシュします。

    `docker push <aws_account_id>.dkr.ecr.<region>.amazonaws.com/hello-repository`


### 1.4.7. AWS ECS クラスターの作成

参考資料：

[AWS Fargate の Linux コンテナによるコンソールの使用開始](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/getting-started-fargate.html)

1. AWS コンソール (https://console.aws.amazon.com/ecs/v2) を開きます。

2. ナビゲーションペインで`クラスター`を選択します。

3. `クラスター`ページで、`クラスターの作成`を選択します。

    - `クラスター設定`で、`クラスター名`に一意の名前を入力します。
    
    - インフラストラクチャを`AWS Fargate`を指定、ほかのオプションはデフォルト値を受け入れ、`作成`を選択します。

### 1.4.8. Amazon ECS タスク実行IAM ロールの作成

参考資料：

[タスク実行 (ecsTaskExecutionRole) ロールの作成](https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/task_execution_IAM_role.html#create-task-execution-role)


タスク実行ロールは、ユーザーに代わって AWS API コールを実行するためのアクセス許可を Amazon ECS コンテナと Fargate エージェントに付与します。タスク実行 IAM ロールは、タスクの要件に応じて必要です。

1. AWS IAM コンソール (https://console.aws.amazon.com/iam/) を開きます。

1. ナビゲーションペインで`ロール`、`ロールの作成` の順に選択します。

2. `信頼されたエンティティタイプ`セクションで、`AWSのサービス`、`Elastic Container Service`の順に選択します。`ユースケース`で、`Elastic Container Service Task`を選択した後、`次へ`を選択します。

    ![create-role-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/1d5e8563-235c-c2c3-4abb-1faacb175ec2.png)

3. `許可ポリシー`セクションで、`AmazonECSTaskExecutionRolePolicy`を検索し、ポリシーを選択します。`次へ`をクリックします。

4. `ロール詳細`で、`ロール名`に `ecsTaskExecutionRole` を入力し、`ロールを作成`を選択します。


### 1.4.9. Fargate タスク定義の作成

1. AWS コンソール (https://console.aws.amazon.com/ecs/v2) を開きます。
   
2. ナビゲーションペインで`タスク定義`を選択します。

3. `新しいタスク定義の作成`、`JSONを使用した新しいタスク定義の作成`の順に選択します。

4. 以下のタスク定義の例をコピーしてボックスに貼り付け、`作成`を選択します。

    ```json
    {
        "family": "hello-world-fargate", 
        "executionRoleArn": "ecsTaskExecutionRole",
        "networkMode": "awsvpc", 
        "containerDefinitions": [
            {
                "name": "hello-world-app", 
                "image": "<aws_account_id>.dkr.ecr.<region>.amazonaws.com/hello-repository:latest", 
                "portMappings": [
                    {
                        "containerPort": 80, 
                        "hostPort": 80, 
                        "protocol": "tcp"
                    }
                ], 
                "essential": true
            }
        ], 
        "requiresCompatibilities": [
            "FARGATE"
        ], 
        "cpu": "256", 
        "memory": "512"
    }
    ```

    > 上記cpu、メモリが最低限です。また、タスク定義時に、必ず`"executionRoleArn": "ecsTaskExecutionRole",`で作成したロールを指定します。`"image": "<aws_account_id>.dkr.ecr.<region>.amazonaws.com/hello-repository:latest",`でECRへプッシュしたイメージのURLを指定します。

### 1.4.10. Fargate サービスの作成

作成したECSクラスターの配下でサービスを作成します。

1. ナビゲーションペインで、`クラスター`を選択してから、作成したクラスターを選択します。

2. ECSクラスターの詳細画面で、`サービス`タブから、`作成`を選択します。
   
3. コンピューティング設定 ((アドバンスト))は、`起動タイプ`を指定、起動タイプは、`Fargate`を指定します。デプロイ設定は、`サービス`を指定します。
    
    ![create-fargate-service-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/3b3b5470-5e11-60f9-3151-0f9d6d1153cb.png)


4. タスク定義は、作成したタスク定義を選択します。サービス名を入力し、必要なタスク数は、デフォルトの１とします。
    
    ![create-fargate-service-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/97b91492-5314-e055-0d5c-2cf5126ada75.png)


5. 「ネットワーキング」は、デフォルトでは、vpc存在しない場合新しく作成してくれます。（デフォルト値を受け入れる）
    
1. ロードバランシングは、Application Load Balancerを指定し、「新しいロードバランサーの作成」を選択します。
    
    - ロードバランサー名：`hello-world-alb`
    - ロードバランス用のコンテナの選択：`hello-world-app 80:80`
    - 新しいリスナーを作成：`80`/`HTTP`
    - ターゲットグループ：`alb-target-gp`/`HTTP`/`HTTP`/`/`
    
    ![create-fargate-service-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/49053fbc-2c9f-354c-7ab6-77dc1c15a6d2.png)

    > awsvpc ネットワークモードではプライベートサブネットだけがサポートされます。タスクはパブリック IP アドレスを受信しません。したがって、アウトバウンドのインターネットアクセスには NAT ゲートウェイが必要であり、またインバウンドのインターネットトラフィックは、ロードバランサーを経由します。

### 1.4.11. セキュリティグループの設定

タスク定義を使用してサービスを作成するときに選択するセキュリティグループには、インバウンドトラフィック用にポート 80 が開いている必要があります。

1. 作成した Fargate サービスの詳細画面から、「設定とネットワーク」を選択し、セキュリティグループを選択します。
    
    ![update-security-group-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/e1f294bb-0d3a-c4a7-9910-544dd1e47464.png)

2. セキュリティグループに次のインバウンドルールを追加します。

    ```
    [Type]: HTTP
    [Protocol]: TCP
    ポート範囲: 80
    ソース: 任意の場所 (0.0.0.0/0)
    ```

    ![update-security-group-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/76e8aa9f-4a02-5206-22b1-7bfea6d744dd.png)

### 1.4.12. サービスの表示

1. 作成した Fargate サービスの詳細画面から、「設定とネットワーク」を選択し、ロードバランサーを選択します。

    ![access-farget-alb-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/a91b92bf-3689-801a-0cd0-99b48f32472c.png)

1. ロードバランサーの詳細画面からDNS名をコピーします。

    ![access-farget-alb-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/7f0dde5b-29d5-be84-087c-cfd273b7cd53.png)

1. ブラウザーでALBのDNS名（例えば、alb-for-fargate-1042693750.ap-northeast-1.elb.amazonaws.com）をアクスタします。「Hello World!」と表示されたら、Fargateのデプロイが成功しました。

    ![access-farget-alb-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/58c26cf1-cf18-3f6e-fb0d-6975d273c55a.png)

### 1.4.13. DNS レコードの更新

1. ALBへRedirectするため、DNSレコードにCNAMEを追加します。今回は、CloudFlareの[DNSサービス](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/)を利用しています。ほかのDNSプロバイダーを利用している場合、DNSプロバイダーのドキュメントを参照してください。

    ![dns-fargate-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/d2a2da04-c341-2f55-2913-c90f3ea82cc0.png)

2. ブラウザーで DNSドメインをアクスタします。「Hello World!」と表示されたら、Fargate側の構築が完了です。

    ![dns-fargate-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/9590469c-f79e-0b28-938d-e9f07dd59ad7.png)


## 1.5. OCI Container Engine for Kubernetes (OKE) への移行

### 1.5.1. OKE クラスタの作成

参考資料：

[コンソールを使用した、クイック作成ワークフローでのデフォルト設定によるクラスタの作成](https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengcreatingclusterusingoke_topic-Using_the_Console_to_create_a_Quick_Cluster_with_Default_Settings.htm#create-quick-cluster)

1. コンソールでナビゲーション・メニューを開き、「開発者サービス」をクリックします。「コンテナとアーティファクト」で、「Kubernetesクラスタ(OKE)」をクリックします。
1. 作業する権限があるコンパートメントを選択します。
1. 「Cluster List」ページで、「クラスタの作成」をクリックします。
1. 「クラスタの作成」ダイアログで、「クイック作成」を選択して「送信」をクリックします。
2. 「クラスタの作成」ページで、新しいクラスタのデフォルトの構成の詳細を次のように指定します:
    
    - 名前：新しいクラスタの名前、例えば、oke-demo-cluster
    - ノード・タイプ：管理対象
    - ノード・シェイプ：VM.Standard.E4.Flex
    - ノード数：1
    
    ![create-oke-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/126eb6b0-5f95-d9cf-a133-5f13ce8161b2.png)

    ![create-oke-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/f197cb52-c9b7-2e26-1ef6-68f004ea583b.png)

    > ノード数は、ノード・プールに作成するワーカー・ノードの数です。この記事では、1ノードとしましたが、高可用性が求める本番環境では、最小構成3ノードがおすすめです。

3. 「次」をクリックして、新しいクラスタ用に入力した詳細を確認します。「確認」ページで「基本クラスタの作成」オプションを選択し、「クラスタの作成」をクリックします。

    ![create-oke-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/751498a2-c6bb-9562-3586-f2e53f93a60f.png)

    > 拡張クラスタおよび基本クラスタの違いは、[OCI ドキュメント](https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengworkingwithenhancedclusters.htm#contengworkingwithenhancedclusters)をご参照ください。この記事では、無料の基本クラスタを選択しましたが、基本クラスタでサポートされない機能が必要な場合、拡張クラスタを選択してください。

4. 最初に、新しいクラスタが、「作成中」ステータスでコンソールに表示されます。クラスタが作成されると、そのステータスは「アクティブ」になります。

    ![create-oke-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/c90b7a19-1363-edd5-1d7f-0cfe987e94ee.png)

### 1.5.2. oci cli の設定

作成したクラスタへアクセスするには、クライアントツールをインストールする必要になります。OKE クラスターの詳細画面から、「クラスタへのアクセス」をクリックして、「ローカル・アクセス」を選択して、oci-cli／kubectlの設定手順を確認できます。

![oci-cli-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/a0e89ed9-1a6f-1555-6443-860c4516ff88.png)

参考資料：

[CLI クイックスタート](https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/cliinstall.htm)

次は、ローカル開発環境（Oracle Linux）での流れです。

1. oci cliをインストールします。

    ```bash
    sudo dnf -y install oraclelinux-developer-release-el8
    sudo dnf install python36-oci-cli
    ```

2. 次のコマンドを使用し、構成ファイルを設定します。

    `oci setup config`

    > このコマンドを使用すると、構成ファイルの作成に必要な情報とAPI公開キーおよび秘密キーの入力が求められます。
    >
    > APIキーを自動生成するか、既存のキーを指定するかが選択可能です。
    >
    > 終わったら、[コンソールを使用して公開キーをアップロード](https://docs.oracle.com/ja-jp/iaas/Content/API/Concepts/apisigningkey.htm#three)してください。

3. 次のコマンドを実行し、構成ファイルを検証します。

    `oci os ns get`

### 1.5.3. kubectl のインストール

[Kubernetesドキュメント](https://kubernetes.io/docs/tasks/tools/)を参照して、kubectlをローカルにインストールします。Oracle Linuxは、yumでインストールできます。

```bash
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/repodata/repomd.xml.key
EOF
```

`sudo yum install -y kubectl`

### 1.5.4. kubectl の設定

`oci cli の設定` と同じように、OKE クラスターの詳細画面から、kubectlの設定する流れを参照して、コマンドをローカル環境で実行します。

1. 次のコマンドを実行し、kubeconfigファイルを格納するディレクトリを作成します。

    `mkdir -p $HOME/.kube`

2. kubeconfigファイルを作成します。パブリック・エンドポイント/プライベート・エンドポイントによって、コマンドを選択して実行します。今回は、パブリック・エンドポイントからアクセスするコマンドを実行します。

    ```bash
    [opc@containerdemo ~]$ oci ce cluster create-kubeconfig --cluster-id ocid1.cluster.oc1.ap-tokyo-1.aaaaaaaaij6wmfhusesaqkqxoe5rbrjoglvuw4h3njsyb3rnncqt2i7wdwza --file $HOME/.kube/config --region ap-tokyo-1 --token-version 2.0.0  --kube-endpoint PUBLIC_ENDPOINT
    New config written to the Kubeconfig file /home/opc/.kube/config
    ```

3. KUBECONFIG環境変数をこのクラスタのファイルに設定するには、次を使用します:

    `export KUBECONFIG=$HOME/.kube/config`

4. `kubectl get nodes`を実行して、kubectlを確認します。ノードが表示されたら、kubectlの設定が成功でした。

    ```bash
    [opc@containerdemo ~]$ kubectl get nodes
    NAME          STATUS   ROLES   AGE   VERSION
    10.0.10.250   Ready    node    35m   v1.28.2
    ```

### 1.5.5. OCIR を利用するための事前準備

OCIR は Oracle が提供するコンテナレジストリのマネージドサービスです。ここでは、作成したコンテナイメージを OCIR にプッシュ（アップロード）します。

OCIR に docker コマンドからアクセスするため、OCI のユーザーアカウントに必要な設定をしていきます。

1. OCIコンソール画面右上の人型のアイコンをクリックし、展開したプロファイルからユーザ名(oracleidentitycloudservice/<ユーザ名>)をクリックします。
1. 下にスクロールした左側にある認証トークンをクリックして、トークンの作成画面に遷移します。
2. トークンの生成ボタンをクリックします。
3. [Geterate Token]ダイアログで、トークンの用途を説明する情報（任意の文字列）を入力し、トークンの生成ボタンをクリックします。
4. ダイアログに生成したトークンが表示されます。Copyという文字列をクリックするとクリップボードにこのトークンがコピーされます。そして閉じるをクリックします。
5. このトークンはあとの手順で利用するため、テキストエディタ等にペーストするなどして控えておいてください

### 1.5.6. OCIR にリポジトリの作成

OCIRにビルドしたコンテナイメージを格納するリポジトリを作成します。

1. OCI コンソールの左上のハンバーガーメニューから、「開発者サービス」-「コンテナ・レジストリ」を選択します。
2. 左メニューにあるコンパートメントのプルダウンメニューから対象のコンパートメントを選択します。
3. 「リポジトリの作成」ボタンをクリックします。
4. 以下の設定を行い、「作成」ボタンをクリックします。

    - コンパートメント：対象のコンパートメント
    - リポジトリ名：hello-repository
    - アクセス：プライベート

    ![create-ocir-repo-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/4fe186fe-a092-5d86-229b-35c230578b04.png)

    > リポジトリのアクセス（パブリック・リポジトリかプライベート・リポジトリか）について、テナンシの管理者グループに属しているか、REPOSITORY_MANAGE権限を付与されている場合のみ、リポジトリを公開できます。リポジトリを公開する場合、インターネット・アクセス権と適切なURLの知識があるユーザーは、リポジトリからイメージをプルできます。リポジトリをプライベートにすると、(テナンシの管理者グループに属するユーザーとともに)リポジトリに対する操作を実行できます。


### 1.5.7. OCIR にコンテナイメージをプッシュする

1. ローカルのイメージ一覧を確認します（イメージがない場合、ECRからイメージをPullしてください）。

    ```bash
    [opc@containerdemo ~]$ docker image ls
    Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
    REPOSITORY                                                                      TAG         IMAGE ID      CREATED       SIZE
    localhost/hello-world                                                           latest      9bf33989ed36  6 days ago    210 MB
    281288470701.dkr.ecr.ap-northeast-1.amazonaws.com/hello-repository              latest      9bf33989ed36  6 days ago    210 MB
    ```

2. OCIR へ Pushするためイメージにタグをつけます。

    `docker tag hello-world [リージョンコード].ocir.io/オブジェクト・ストレージ・ネームスペース]/[リポジトリ名]/hello-world`

    ```bash
    [opc@containerdemo ~]$ docker tag hello-world nrt.ocir.io/testtenancy/hello-repository/hello-world
    Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
    ```

    イメージタグを省略した場合、タグは latest と見なされます。イメージタグを指定する場合、次の様に設定します。
    
    `docker tag hello-world [リージョンコード].ocir.io/オブジェクト・ストレージ・ネームスペース]/[リポジトリ名]/hello-world:tag`

    > ご自身の環境に合わせて、[ドキュメント](https://docs.oracle.com/ja-jp/iaas/Content/Registry/Concepts/registryprerequisites.htm#regional-availability)から適切なリージョンコードを見つけてください。
    > オブジェクト・ストレージ・ネームスペースは、OCIコンソール画面右上の人型のアイコンをクリックし、展開したプロファイルからテナンシ:<テナンシ名>から確認します。
    > ![object-storage-namespace-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/4022a9c9-3bff-6d96-59d8-939ca6965552.png)



2. イメージのタグを確認します。

    ```bash
    [opc@containerdemo ~]$ docker image ls
    Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
    REPOSITORY                                                                      TAG         IMAGE ID      CREATED       SIZE
    localhost/hello-world                                                           latest      9bf33989ed36  7 days ago    210 MB
    281288470701.dkr.ecr.ap-northeast-1.amazonaws.com/hello-repository              latest      9bf33989ed36  7 days ago    210 MB
    nrt.ocir.io/testtenancy/hello-repository/hello-world                         latest      9bf33989ed36  7 days ago    210 MB
    ```

1. 以下のコマンドでOCIRにログインします。Login Succeededというメッセージが表示されれば、ログイン成功です。

    `docker login [リージョンコード].ocir.io`

    例えば、東京リージョン(nrt)をご利用の場合は、以下のコマンドでログインします。

    `docker login nrt.ocir.io`

    ユーザー名、パスワードの入力を求めるメッセージが表示されますので、以下のように入力してください。

    - ユーザー名: `[オブジェクト・ストレージ・ネームスペース]/[ユーザー名]` （例: `testtenancy/oracleidentitycloudservice/xxxxx.yyy@oracle.com`）

    - パスワード: `[OCIR を利用するための事前準備で 作成したトークン文字列]`

    > ユーザー名は、OCIコンソール画面右上の人型のアイコンをクリックし、展開したプロファイルからユーザーから確認します。取得したユーザー名を`[オブジェクト・ストレージ・ネームスペース]/[ユーザー名]`の形で連結してログインユーザーとして使います。
    > ![oci-username-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/3f03bf1b-abd1-4357-e816-0abd2b2176c2.png)

1. これで準備が整いましたので、実際にOCIRにイメージをプッシュします。以下のコマンドを実行してください。

    `docker image push [リージョンコード].ocir.io/[オブジェクト・ストレージ・ネームスペース]/[リポジトリ名]/hello-world`

    例えば、以下のように指定します。

    `docker image push hello-world nrt.ocir.io/testtenancy/hello-repository/hello-world`

    以下のような実行結果となれば、プッシュが成功しています。
    ```bash
    [opc@containerdemo ~]$ docker image push hello-world nrt.ocir.io/testtenancy/hello-repository/hello-world
    Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
    Getting image source signatures
    Copying blob d2e23825b905 done
    Copying blob 548a79621a42 done
    Copying blob 475b33db679c done
    Copying blob 8607ef4f2ff2 done
    Copying config 9bf33989ed done
    Writing manifest to image destination
    ```

2. OCIRにコンテナが保存されていることを確認してみましょう。OCIコンソールの画面で左上のメニューを展開し、開発者サービス－コンテナ・レジストリをクリックします。リポジトリの一覧が表示されます。この中に、指定した名前のコンテナがあることを確認してください。(デフォルトでは、イメージがルートコンパートメントにプッシュされますので、ルートコンパートメントの配下で確認してください)

    ![ocir-image-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/d1378546-60dd-4c47-ddf8-2f4410146b80.png)

### 1.5.8. OKEへのデプロイ

1. kubectlを使用してDockerレジストリ・シークレットを作成する必要があります。シークレットには、イメージをプルするときに使用するOracle Cloud Infrastructureの資格証明が含まれます。

    `kubectl create secret docker-registry ocisecret --docker-server=[リージョンコード].ocir.io --docker-username=[オブジェクト・ストレージ・ネームスペース]/[ユーザー名] --docker-password='[OCIR を利用するための事前準備で 作成したトークン文字列]' --docker-email=<email-address>`

    例えば、

    ```bash
    [opc@containerdemo hello-world]$ kubectl create secret docker-registry ocisecret --docker-server=nrt.ocir.io --docker-username=testtenancy/oracleidentitycloudservice/xxxxx.yyy@oracle.com --docker-password='ds)}d}yv79Ks<+BT5<:[' --docker-email=xxxxx.yyy@oracle.com
    secret/ocisecret created
    ```


2. OKEを始めとして、Kubernetesのクラスターにコンテナをデプロイするには、クラスター上の配置情報をmanifestと呼ばれるファイルに記述しておく必要があります。まずは、Deploymentを定義するファイル`hello-world.yaml`を作成します。
    
    ```yml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-world-deployment
      labels:
        app: hello-world
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: hello-world
    
      template:
        metadata:
          labels:
            app: hello-world
        spec:
          containers:
          - name: hello-world
            image: nrt.ocir.io/testtenancy/hello-repository/hello-world:latest
            ports:
            - containerPort: 80
          imagePullSecrets:
            - name: ocisecret
    
    ```

    > このファイルによって、サンプルアプリケーションのコンテナが、クラスター上にどのように配置されるかが定義されています。例えば、`replicas:3`という記述は、このコンテナが、3つ立ち上げられて冗長構成を取るということを意味しています。`containers:`という記述は、実際にクラスター上で動かすコンテナイメージが指定されています。`imagePullSecrets:`は、作成したレジストリ・シークレットを指定します。Deploymentの詳細については、[Kubernetesドキュメント](https://kubernetes.io/ja/docs/concepts/workloads/controllers/deployment/)を参照してください。 

3. 次に、`hello-world-service.yaml`というmanifestファイルの内容を作成します。
    
    ```yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: hello-world-service
      labels:
        app: hello-world
      annotations:
        oci.oraclecloud.com/load-balancer-type: "lb"
        service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
        service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
        service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "30"
    spec:
      type: LoadBalancer
      selector:
        app: hello-world
      ports:
        - port: 80
    ```
    
    > このmanifestファイルは、クラスターに対するリクエストのトラフィックを受け付ける際のルールを定義しています。`type: LoadBalancer`という記述は、クラスターがホストされているクラウドサービスのロードバランサーを自動プロビジョニングし、そのLBに来たトラフィックをコンテナに届けるという意味です。LoadBalancerタイプのKubernetesサービスのOCIロード・バランサをプロビジョニングする方法については[OKEドキュメント](https://docs.oracle.com/en-us/iaas/Content/ContEng/Tasks/contengcreatingloadbalancers-subtopic.htm#contengcreatingloadbalancers_subtopic)を参照してください。

1. それでは、Kubernetes上でサンプルアプリケーションのコンテナを動かしてみます。まずは、クラスターを区画に分けて管理するための領域である、namespaceを作成します。以下のコマンドで、namespace名は任意の文字列を指定できます。今回は”hello-world-demo”というnamespace名で作成します。

    `kubectl create namespace hello-world-demo`

1. デフォルトのNamespaceを上記で作成したものに変更しておきます。これを行うと、以降、kubectlの実行の度にNamespaceを指定する必要がなくなります。

    `kubectl config set-context $(kubectl config current-context) --namespace=hello-world-demo`
    
1. 次に、manifestファイルをクラスターに適用し、PodやServiceをクラスター内に作成します。

    ```bash
    [opc@containerdemo hello-world]$ kubectl apply -f hello-world.yaml
    deployment.apps/hello-world-deployment created
    
    [opc@containerdemo hello-world]$ kubectl apply -f hello-world-service.yaml
    service/hello-world-service created
    ```

1. 以下のコマンドを実行して、リソースの構成が完了しているかどうかを確認することができます。

    ```bash
    [opc@containerdemo hello-world]$ kubectl get pod,service
    NAME                                          READY   STATUS    RESTARTS   AGE
    pod/hello-world-deployment-795fbc7f8c-f4k6n   1/1     Running   0          6m58s
    pod/hello-world-deployment-795fbc7f8c-jg72m   1/1     Running   0          7m2s
    pod/hello-world-deployment-795fbc7f8c-wrvq4   1/1     Running   0          12m
    
    NAME                          TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
    service/hello-world-service   LoadBalancer   10.96.70.121   155.248.171.21   80:30947/TCP   3d21h
    ```
    
    > すべてのPodのSTATUSがRunnigであることと、`hello-world-service`という名前のServiceがあることが確認できれば、リソースの作成は完了です（ServiceのEXTERNAL-IPは、ロードバランサーが実際に作成されるまで表示されません。その場合は少し時間を置いて上記コマンドを再実行してください）。
    >
    > 上の例では、IPアドレス155...***の80番ポートでロードバランサーが公開されておりここにリクエストを送信すると、アプリケーションにアクセスできることを意味しています。このIPアドレスをテキストエディタ等に控えておいてください。

### 1.5.9. DNS 更新

トラフィックをECS FargateからOKE に切り替えるため、DNS側の設定を修正します。

1. AWS ECS FargateのALBへRedirectするCNAMEレコードをAレコードに変更し、IPv4のアドレスをOKEのロードバランサーのIPに変更します。

    ![update-dns-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/98230134-783e-9b88-953b-0911f4356208.png)

2. nslookupなどコマンドを実行し、DNSレコードの変更が反映されたことを確認します。OKEのLBのIPと表示されたら、DNSレコードの変更が反映されています。

    ```bash
    [opc@containerdemo hello-world]$ nslookup hello-world.xxxxxx.top
    Name:	hello-world.xxxxxx.top
    Address: 155.248.171.21　→　OCI LBのIP
    ```

2. ブラウザーで DNSドメインをアクスタします。「Hello World!」と表示されたら、OKE への移行が完了です。

    ![dns-fargate-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534261/57400a67-ae36-f9d8-9ead-b2421de875ca.png)