EKSにデプロイしたGitLabとS3を連携させる

# はじめに
EKSにHelmでGitLabをデプロイする際、デフォルトではminioをオブジェクトストレージとして使用していますが、今回はS3で代替する方法を説明します。
EKS環境は構築されていることを前提としています。

# 環境情報
macOS Mojave 10.14.1
EKS 1.14
Helm 3.0.1
kubectl v1.14.7-eks-1861c5
AWC CLI 1.16.292
kube2iam Helm Chart 2.0.1
GitLab Helm Chart 3.0.4

# 手順
大きく分けて4つの手順があります。
1. S3バケットの用意
2. kube2iamの設定
3. Kubernetes Secretの作成
4. GitLabのデプロイ

## 1. S3バケットの用意
事前にS3バケットを作成しておく必要があります。全部で9個のバケットを作成します。
1個のバケットでパスで分けれれば楽なんですがまだ対応していないようです。

バケットと格納物の対応は下表になります。


||バケット|格納物|
|:--|:--|:--|
|1|gitlab-artifacts|GitLab CIのartifacts|
|2|gitlab-backups|バックアップファイル|
|3|gitlab-lfs|GitLab LFSで使用されるファイル|
|4|gitlab-mr-diffs|マージリクエストのdiff|
|5|gitlab-packages|アプリや依存ツールのパッケージ|
|6|gitlab-pseudo|アプリデータを安全にエクスポートしたもの|
|7|gitlab-registry|Dockerイメージ|
|8|gitlab-tmp|リストアを行うときに一時的に退避しておく現存データ|
|9|gitlab-uploads|アイコン画像などのファイル|

バケット名はリージョンで一意である必要があるので実際に作成するときはprefixを付けましょう。
今回は`s3-dev-`にしています。

<img width="1181" alt="スクリーンショット 2020-02-23 15.19.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/4a82ff32-6aee-1e5d-099c-1d6120dc68f1.png">


## 2. kube2iamの設定
### 2.1. IAMロールの作成
PodがS3にアクセスするためにkube2iamを使ってIAMロールをPodにアタッチします。
他にもIAMユーザの権限を与えるか、IAMロールをWorker Nodeにアタッチする方法もありますが、前者はアクセスキーとシークレットアクセスキーをPodに設定しないといけず、後者は関係ないPodもS3にアクセスできてしまうという点からkube2iamを採用します。


まずはWorker Nodeに対する設定です。
次のようにIAMポリシーを定義したjsonファイルをまず作成します。

```json:assume-role-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "*"
    }
  ]
}
```

次にjsonファイルからIAMポリシーを作成します。

```console
$ aws iam create-policy \
  --policy-name assume-role-policy \
  --policy-document file://assume-role-policy.json
```

Worker NodeにアタッチされているIAMロールにこのポリシーをアタッチします。
`<NODE_INSTANCE_ROLE>`と`<YOUR_ACCOUNT>`は自分独自のものに代替してください。

```console
$ aws iam attach-role-policy \
  --role-name <NODE_INSTANCE_ROLE> \
  --policy-arn arn:aws:iam::<YOUR_ACCOUNT>:policy/assume-role-policy
```

Worker Nodeへの設定は完了したので、今度はPodについて設定を行います。
次のようにIAMロールを定義したjsonファイルを作成します。

```json:kube2iam-role.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<YOUR_ACCOUNT>:role/<NODE_INSTANCE_ROLE>"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

次にjsonファイルからIAMロールを作成します。

```console
$ aws iam create-role \
  --role-name s3-full-access-role \
  --assume-role-policy-document file://kube2iam-role.json
```

S3のフルアクセス権限をIAMロールにアタッチします。

```console
$ aws iam attach-role-policy \
  --role-name s3-full-access-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
```

### 2.2. デプロイ
IAMロールの作成は完了したのでどのPodにIAMロールをつけるかを見つけて実際に付与するためのkube2iamをHelmでデプロイします。
valuesは独自のものを作成します。

```yaml:kube2iam-values.yaml
host:
  iptables: true
  interface: eni+
extraArgs:
  auto-discover-base-arn: ""
rbac:
  create: true
```

これをデプロイすればkube2iamの設定は終わりです。

```console
$ helm install \
  --namespace kube-system \
  --values kube2iam-values.yaml \
  --version 2.0.1 \
  kube2iam stable/kube2iam
```

## 3. Kubernetes Secretの作成
S3へのアクセス情報をSecretとして定義していきます。
3種類のSecretを作成する必要があります。

### 3.1. Registy
Dockerレジストリへのアクセス設定です。
使用するS3バケットの情報をyamlファイルとして保存します。

```yaml:registry-storage.yaml
s3:
  bucket: s3-dev-gitlab-registry
  v4auth: true
  region: ap-northeast-1
```

このyamlファイルからSecretを作成します。

```console
$ kubectl create secret generic registry-storage \
  --from-file=config=registry-storage.yaml
```

### 3.2. LFS, Artifacts, Uploads, Packages, Diffs, Pseudonymizer
LFS, Artifacts, Uploads, Packages, Diffs, Pseudonymizerに使うS3バケットへのアクセス設定を行います。
使用するS3バケットの情報をyamlファイルとして保存します。

```yaml:rails-storage.yaml
provider: AWS
use_iam_profile: true
region: ap-northeast-1
```

このyamlファイルからSecretを作成します。

```console
$ kubectl create secret generic rails-storage \
    --from-file=connection=rails-storage.yaml
```

### 3.3. Backups
バックアップファイルを格納するS3バケットへのアクセス設定を行います。
使用するS3バケットの情報をyamlファイルとして保存します。

```config:storage.config
[default]
bucket_location = ap-northeast-1
```

このファイルからSecretを作成します。

```console
$ kubectl create secret generic storage-config \
  --from-file=config=storage.config
```

## 4. GitLabのデプロイ
S3バケットにアクセスできるようにHelm Chartのvaluesを編集する必要があります。
ここでは独自のvaluesを作成していくことにします。

必要最低限の設定は次のようになります。

```yaml
global:
  minio:
    enabled: false
  appConfig:
    lfs:
      bucket: s3-dev-gitlab-lfs
      connection:
        secret: gitlab-rails-storage
        key: connection
    artifacts:
      bucket: s3-dev-gitlab-artifacts
      connection:
        secret: gitlab-rails-storage
        key: connection
    uploads:
      bucket: s3-dev-gitlab-uploads
      connection:
        secret: gitlab-rails-storage
        key: connection
    packages:
      bucket: s3-dev-gitlab-packages
      connection:
        secret: gitlab-rails-storage
        key: connection
    externalDiffs:
      enabled: true
      bucket: s3-dev-gitlab-mr-diffs
      connection:
        secret: gitlab-rails-storage
        key: connection
    pseudonymizer:
      configMap:
      bucket: s3-dev-gitlab-pseudo
      connection:
        secret: gitlab-rails-storage
        key: connection
    backups:
      bucket: s3-dev-gitlab-backups
      tmpBucket: s3-dev-gitlab-tmp
  registry:
    bucket: s3-dev-gitlab-registry
registry:
  storage:
    secret: registry-storage
    key: config
  annotations:
    iam.amazonaws.com/role: s3-full-access-role
gitlab:
  unicorn:
    annotations:
      iam.amazonaws.com/role: s3-full-access-role
  sidekiq:
    annotations:
      iam.amazonaws.com/role: s3-full-access-role
  task-runner:
    annotations:
      iam.amazonaws.com/role: s3-full-access-role
    backups:
      objectStorage:
        config:
          secret: storage-config
          key: config
```

気にすべき点は以下3点です。

* `globa.minio.enabled=false`にする
* S3バケット情報とSecret情報を紐づける
* PodのannotationsにIAMロール情報を書く

これだけの設定だけだと`prometheus`など諸々installしてしまいます。
検証のためなので不要なものをinstallしないようにします。

実際に使うvaluesは以下になります。
`global.hosts.domain`の値は自分で所有するものに書き換えましょう。

```yaml:gitlab-values.yaml
global:
  edition: ce
  hosts:
    domain: sample.com
    https: false
  ingress:
    configureCertmanager: false
    tls:
      enabled: false
  minio:
    enabled: false
  appConfig:
    lfs:
      bucket: s3-dev-gitlab-lfs
      connection:
        secret: gitlab-rails-storage
        key: connection
    artifacts:
      bucket: s3-dev-gitlab-artifacts
      connection:
        secret: gitlab-rails-storage
        key: connection
    uploads:
      bucket: s3-dev-gitlab-uploads
      connection:
        secret: gitlab-rails-storage
        key: connection
    packages:
      bucket: s3-dev-gitlab-packages
      connection:
        secret: gitlab-rails-storage
        key: connection
    externalDiffs:
      enabled: true
      bucket: s3-dev-gitlab-mr-diffs
      connection:
        secret: gitlab-rails-storage
        key: connection
    pseudonymizer:
      configMap:
      bucket: s3-dev-gitlab-pseudo
      connection:
        secret: gitlab-rails-storage
        key: connection
    backups:
      bucket: s3-dev-gitlab-backups
      tmpBucket: s3-dev-gitlab-tmp
  registry:
    bucket: s3-dev-gitlab-registry
  time_zone: Tokyo
upgradeCheck:
  enabled: false
certmanager:
  install: false
nginx-ingress:
  controller:
    replicaCount: 2
  defaultBackend:
    replicaCount: 1
prometheus:
  install: false
registry:
  hpa:
    minReplicas: 1
  storage:
    secret: registry-storage
    key: config
  annotations:
    iam.amazonaws.com/role: s3-full-access-role
gitlab-runner:
  install: false
gitlab:
  gitlab-shell:
    enabled: false
  gitlab-exporter:
    enabled: false
  unicorn:
    annotations:
      iam.amazonaws.com/role: s3-full-access-role
  sidekiq:
    annotations:
      iam.amazonaws.com/role: s3-full-access-role
  task-runner:
    annotations:
      iam.amazonaws.com/role: s3-full-access-role
    backups:
      objectStorage:
        config:
          secret: storage-config
          key: config
```

このvaluesを使用してHelmでデプロイします。

```console
$ helm install \
  --namespace dafault \
  --values gitlab-values.yaml \
  --version 3.0.4 \
  dev-gitlab gitlab/gitlab
```

Route53等に名前解決の設定を入れたら完了です。

# 確認
GitLabにアクセスします。

<img width="1440" alt="スクリーンショット 2020-02-23 16.20.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/123ee46e-81dd-86cc-cacf-ed3ced6cff3b.png">

rootユーザの初期パスワードは下記コマンドで確認できます。
`<RELEASE>`はHelmのリリース名です。今回なら`dev-gitlab`にあたります。

```console
$ kubectl get secret <RELEASE>-gitlab-initial-root-password -ojsonpath='{.data.password}' | base64 --decode
```

S3へのアクセスを確認するにはアイコン画像を変えてみるのが一番簡単な方法です。
試しに自分のアイコン画像を変えてみます。

<img width="1440" alt="スクリーンショット 2020-02-23 16.28.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/7e89802c-646b-4931-6acc-dd674ad92916.png">


AWSコンソールでS3バケットを確認してみます。
`avatar.png`として格納されていることが分かります。
<img width="1440" alt="スクリーンショット 2020-02-23 16.30.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/fd27fcb4-47e9-1174-a74b-379aebf19586.png">

# おわりに
EKSにHelmでデプロイしたGitLabとS3を連携させる手順を説明しました。

作成しなければならないS3バケットが多いこととSecret作成が面倒なことが難点ですが、やはりminioよりS3を使ったほうがファイル管理は楽だと思います。

また、Gitリポジトリデータが増えていくとバックアップファイルもその分大きくなっていきます。
これをminioで管理していくと料金もかさばっていきます。

以上のことからもS3を利用することをおすすめします。