OCIのDevOpsを使用してOKEへのDevOps実施

## 概要
OCIのDevOpsを以下のリンクを参考に実施しました。

[KubernetesでサンプルアプリケーションのデプロイとCI/CDを体験してみよう](https://oracle-japan.github.io/ocitutorials/cloud-native/oke-for-intermediates/)

## 構成
ソースコードリポジトリはGitHubを利用しています。
OCI DevOps PipelineにてBuildとコンテナレジストリへのPushとKubernetesのマニフェストを使用したdeployを行っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/b309b044-7488-c06c-acb5-171b4f43043a.png)
					
									
## 前提
- Webコンテンツを作成してGitHubリポジトリにPush済み
- OCI OKEクラスターを構築済み

## ポリシー設定
ポリシーを適用するグループを定義します。
動的グループ：OCI_DevOps_Dynamic_Group
一致ルール：以下のいずれかに該当
　　　*instance.compartment.id = ‘コンパートメントOCID’,*
　　　*resource.compartment.id = ‘コンパートメントOCID’*

今回のDevOpsを行うために以下のポリシーを設定します。
- OCI DevOpsが自身が持つ各機能を利用可能にするポリシー
*Allow dynamic-group OCI_DevOps_Dynamic_Group to manage devops-family in compartment ‘コンパートメント名’*
- OCI DevOpsがOCIRやアーティファクト・レジストリを管理可能とするポリシー
*Allow dynamic-group OCI_DevOps_Dynamic_Group to manage all-artifacts in compartment ‘コンパートメント名’*
- OCI DevOpsがOCI Notificationsサービス(後続の手順で作成予定)を利用可能とするポリシー
*Allow dynamic-group OCI_DevOps_Dynamic_Group to use ons-topics in compartment ‘コンパートメント名’*
- OCI DevOpsがOKEを管理するためのポリシー
*Allow dynamic-group OCI_DevOps_Dynamic_Group to manage cluster-family in compartment ‘コンパートメント名’*

参考
[KubernetesでサンプルアプリケーションのデプロイとCI/CDを体験してみよう　1.ポリシー作成](https://oracle-japan.github.io/ocitutorials/cloud-native/oke-for-intermediates/#1%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC%E4%BD%9C%E6%88%90)

## コンテンツ作成とGitHubへのPush
サンプルアプリケーションとしてNginxを使用しました。

     |--build_spec.yaml
     |--Dockerfile
     +--conf
     |  +--NGINX構成ファイル
     +--src
        +--コンテンツ

- build_spec.yaml
```build_spec.yaml
version: 0.1
component: build
timeoutInSeconds: 10000
shell: bash
env:
  variables:
    container_name: 【コンテナ名】
    container_version: 1.0
  exportedVariables:
    - tag

steps:
  - type: Command
    name: "Docker image build"
    timeoutInSeconds: 4000
    command: |
      docker build -t ${container_name} .
      tag=${container_version}
    onFailure:
      - type: Command
        command: |
          echo "Failure successfully handled"
        timeoutInSeconds: 60

outputArtifacts:
  - name: 【コンテナ名】
    type: DOCKER_IMAGE
    location: 【コンテナ名】:latest
```

## コンテナ・レジストリ作成
コンテナイメージの格納先を作成します。
- OCIナビゲーションメニューから開発者サービス>>コンテナとアーティファクト>>コンテナ・レジストリを選択して「リポジトリの作成」を押下
- リポジトリ名に【コンテナ名】を入力して「作成」を押下

## アーティファクト・レジストリでのリポジトリ作成
kubernetesマニフェストファイルを設定します。
- deployment.yamlをローカルに準備
```deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: 【app名】-deployment # app名は任意
  labels:
    app: 【app名】
spec:
  replicas: 1   # テストなのでreplicaは1つ
  selector:
    matchLabels:
      app: 【app名】
  template:
    metadata:
      labels:
        app: 【app名】
    spec:
      containers:
      - name: 【コンテナ名】
        image: 【コンテナ・レジストリ】/【ネームスペース】/【コンテナ名】:1.0 #コンテナ・レジストリのイメージへの完全修飾パス
        imagePullPolicy: Always
        ports:
        - containerPort: 8080  # nginx confファイルで設定したnginxのlisten port
          protocol: TCP
      imagePullSecrets:
        - name: 【secret】 # 事前にOCIRのlogin情報をsecretとして登録要
---
apiVersion: v1
kind: Service
metadata:
  name: 【app名】-svc
spec:
  selector:
    app: 【app名】
  ports:
    - port: 8085         # ServiceのExpose port
      targetPort: 8080   # nginx confファイルで設定したnginxのlisten port
      nodePort: 30990    # nodeで公開するport
  type: NodePort
```
- OCIナビゲーションメニューから開発者サービス>>コンテナとアーティファクト>>アーティファクト・レジストリを選択して「リポジトリの作成」を押下
- 名前を設定して「作成」を押下
- 「アーティファクトのアップロード」を押下
- アーティファクト・パスにマニフェストファイル(deployment.yaml)、アーティファクトのバージョンを設定
- 今回はマニフェストファイルをOCI CLI実行可能なLinuxからアップロードするのでCLIを選択すると投入コマンドが表示されるのでコピー
- Linuxにてペーストしてマニフェストファイルを指定して実行
```
oci artifacts generic artifact upload-by-path \
  --repository-id ocid1.artifactrepository.oc1.***** \
  --artifact-path deployment.yaml \
  --artifact-version 1.0 \
  --content-body ./deployment.yaml  #アップロードするマニフェスト
```
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/8dc87d08-79ed-7e1d-899c-806d64ed4983.png">

## トピック作成
DevOpsの通知先(メール等)としてのトピックを作成します。

[トピックの作成](https://docs.oracle.com/ja-jp/iaas/Content/Notification/Tasks/create-topic.htm)

## Vault作成
GitHub個人用アクセストークンを保管するためにVaultを作成します。

Vaultの作成
キーを管理するVaultを作成
[Vaultの作成](https://docs.oracle.com/ja-jp/iaas/Content/KeyManagement/Tasks/managingvaults_topic-To_create_a_new_vault.htm)

マスター暗号化キーの作成
Vault配下でGitHub個人用アクセストークンを暗号化するキーの作成
[マスター暗号化キーの作成](https://docs.oracle.com/ja-jp/iaas/Content/KeyManagement/Tasks/managingkeys_topic-To_create_a_new_key.htm)

Vaultでのシークレットの作成
Vault配下でGitHub個人用アクセストークンを格納します。
アクセストークンは前述のマスター暗号化キーによって暗号化されます。
[Vaultでのシークレットの作成](https://docs.oracle.com/ja-jp/iaas/Content/KeyManagement/Tasks/managingsecrets_topic-To_create_a_new_secret.htm)

参考
[OCI Vault 機能概要と特徴](https://speakerdeck.com/oracle4engineer/oci-vault-ji-neng-gai-yao-tote-zheng)

## DevOps作成
CI/CDパイプラインを設定します。
- DevOpsプロジェクトの作成
    - OCIナビゲーションメニューから開発者サービス>>DevOps>>プロジェクトを選択して「DevOpsプロジェクトの作成」を押下
    - トピックの選択で作成したトピックを選択
    - 「DevOpsプロジェクトの作成」を押下
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/8359431c-7bc0-9cd3-4128-223582413772.png">

- 外部接続
GitHub接続設定を行います。
    - DevOpsプロジェクト・リソースから外部接続を選択し「外部接続の作成」を押下
    - 名前を設定
    - タイプはGitHubを設定
    - ボールト・シークレットはGitHub個人用アクセストークンを格納したVaultを選択
    - 「作成」を押下

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/c6fc1a40-5c54-5795-1108-8911057cbf39.png">

- コード・リポジトリ
GitHubコード・リポジトリのクローン設定を行います。
    - DevOpsプロジェクト・リソースからコード・リポジトリを選択し「リポジトリのミラー化」を押下
    - 接続は外部接続で作成した接続を選択
    - リポジトリはGitHubのリポジトリが読み込まれるので該当のリポジトリを選択
    - 名前を設定
    - 「リポジトリのミラー化」を押下
    - ミラーリングが成功するとコードリポジトリ内容が表示される

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/736cb294-9ad7-ffee-deb8-3046ade8bf25.png">

- 環境
　OKEクラスター情報を登録します。
    - DevOpsプロジェクト・リソースから環境を選択し「環境の作成」を押下
    - 環境タイプはOracle Kubernetesエンジンを選択
    - 名前を設定して「次」を押下
    - リージョンを選択
    - クラスタは対象のOKEクラスターを選択
    - 「環境の作成」を押下

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/354b4f73-4961-9c7d-8e2b-170c4928b79c.png">

- アーティファクト (Dockerイメージ)
DockerイメージPush先を設定します。
    - DevOpsプロジェクト・リソースからアーティファクトを選択し「アーティファクトの作成」を押下
    - 名前を設定
    - タイプはコンテナイメージレポジトリを選択
    - コンテナ・レジストリのイメージへの完全修飾パスでコンテナ・レジストリ作成で作成した内容を以下のように入力
            - 【コンテナ・レジストリ】/【ネームスペース】/【コンテナ名】:${tag}
            - コンテナ・レジストリは東京であればnrt.ocir.io
            - タグは${tag}を設定　(build_spec.yaml 環境変数tag)　
    - 「追加」を押下
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/d9b061ea-8757-552f-fa08-0c6e3d07fe94.png">
       
- アーティファクト (Kubernetesマニフェスト)
Kubernetesマニフェストを指定します。
    - DevOpsプロジェクト・リソースからアーティファクトを選択し「アーティファクトの作成」を押下
    - 名前を設定
    - タイプはKubernetesマニフェストを選択
    - アーティファクト・ソースはアーティファクト・レジストリ・リポジトリを選択
    - アーティファクト・レジストリ・リポジトリは前述で作成したアーティファクト・レジストリ・リポジトリを選択
    - アーティファクト設定のアーティファクトパスはマニフェストファイル(deployment.yaml)を設定
    - アーティファクト設定のバージョンは${tag}を設定　(build_spec.yaml 環境変数tag)
    - 「追加」を押下
    
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/cb7e6b03-053d-b5e9-b551-a41e4568e8d9.png">

- ビルド・パイプライン　マネージドビルド
　コンテナイメージビルドを行うためのパイプラインを作成します。
     - DevOpsプロジェクト・リソースからビルド・パイプラインを選択し「ビルド・パイプラインの作成」を押下
     - 名前を設定して「作成」を押下
    - 「ステージの追加」を押下
    - ステージはマネージドビルドを選択して「次」を押下
    - ステージ名を設定
    - プライマリ・コード・リポジトリはコード・リポジトリで作成したリポジトリを選択
    - 「追加」を押下

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/880a6888-9bb2-8b56-4a71-8c40e17866d1.png">

- ビルド・パイプライン　アーティファクトの配信
　コンテナPushを行うためのパイプラインを追加します。
    - 作成したビルド・パイプラインの最後のステージの+マークをクリックしてステージの追加を選択
    - ステージはアーティファクトの配信を選択して「次」を押下
    - ステージ名を設定
    - アーティファクトは前述のDockerイメージを選択
    - ビルド構成/結果アーティファクト名は【コンテナ名】を設定
    - 「追加」を押下
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/fbe856fc-45ec-4109-1ace-718d75c2186b.png">

- トリガー
　GitHubコード・リポジトリのクローンを行った際にPushがあればビルドパイプラインを開始します。
     - DevOpsプロジェクト・リソースからトリガーを選択し「トリガーの作成」を押下
     - 任意の名前を設定
     - ソース接続はGitHubを選択
     - 「アクションの追加」を押下
     - ビルド・パイプラインは前述で作成したビルド・パイプラインを選択
     - イベントオプションはプッシュを選択
     - 「作成」を押下

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/a82f65c4-6f19-06cb-2c7f-915a408201e5.png">

- CDパイプラインの構築
Kubernetesマニフェストを使ったDeployを行うためのパイプラインを追加します。
     - DevOpsプロジェクト・リソースからデプロイメント・パイプラインを選択し「パイプラインの作成」を押下
    - パイプライン名を設定して「パイプラインの作成」を押下
    - 「ステージの追加」を押下
    - Kubernetesクラスタにマニフェストを適用を選択して「次」を押下
    - ステージ名を設定
    - OKE環境を前述の環境で作成したクラスターを選択
    - アーティファクトの選択で前述のアーティファクトで作成したKubernetesマニフェストを選択
    - 「追加」を押下
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/6ccc2dce-31e0-72bd-6969-2e3c69391715.png">

- CIパイプラインへのCDパイプライン起動ステップの追加
作成したCDパイプラインをCIパイプラインに追加します
    - DevOpsプロジェクト・リソースからビルド・パイプラインを選択し作成したパイプラインを選択
    - 作成した最後のステージの+マークをクリックしてステージの追加を選択
    - デプロイメントのトリガーを選択して「次」を押下
    - ステージ名を設定
    - 作成したデプロイメント・パイプラインの選択
    -「追加」を押下
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/dd0ac361-265b-f396-6dd8-a63caf81897d.png">

- ログ
　ビルド状況を保管するログを設定します
    - DevOpsプロジェクト・リソースからログを選択し作成しログの有効化を有効に変更
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/89e743be-4b4d-64ca-137d-c25f6c6c710f.png">

## 実行結果
- 手動実行
正常に実行するか確認するため手動実行します。
    - DevOpsプロジェクト・リソースからビルド・パイプラインを選択し作成したパイプラインを選択
    - 「手動実行の開始」を押下
    - 以下のようにビルド実行の進捗状況がすべて緑のチェックマークになると成功です。
<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/8941035a-1ca1-fcab-447b-368de3175d64.png">

- Pod起動確認
kubectlコマンドおよびcurlコマンドを実行して正常に起動できたことを確認します。
```
[user@linux]$ kubectl get po   
NAME                                           READY   STATUS    RESTARTS   AGE
pod/docker-nginx-deployment-5d44df6579-5mrqp   1/1     Running   0          43s

[user@linux]$ curl -I http://【node ip address】:30990
HTTP/1.1 200 OK

```