EKSにデプロイしたNexusのblob storeをEBSからS3に移行させる


はじめに

Sonatype Nexusはmaven, gradle, npm, dockerなどに対応したプライベートリポジトリマネージャーです。
リポジトリ内のファイルの保存方式はFILEとS3のどちらかを選ぶことができ、前者はEBSなどに、後者はその名の通りS3に保存されます。
ディスク容量の監視を不要とし料金も安くしたいときにはS3にしておいた方がいいです。

今回はEBSにFILE方式で保存されている既存データをS3に移行させる方法を説明します。
NexusはEKSにデプロイすることを前提としています。

環境

macOS Mojave 10.14.1
Helm: 3.0.1
EKS: 1.14
Nexus Helm Chart: 1.22.0

前準備

データ移行の前にNexusデプロイ、リポジトリ作成、データ格納を行います。
EKS、S3などのAWSリソースやALB Ingress Controller、kube2iamなどのKubernetesリソースはすでにデプロイ済みであることを前提とします。

Nexusのデプロイ

Helmを使ってNexusをデプロイします。
templateを少し修正する必要があるのでhelm fetchで公式Helm Chartをローカルに落とします。

$ helm fetch stable/sonatype-nexus --version 1.22.0
$ tar -xvzf sonatype-nexus-1.22.0.tgz

Nexus Helm Chartのディレクトリ構造は下記となります。
valuesにはmy-values.yamlを自分で作って適用させます。
*が付いているファイルを編集します。

├── Chart.yaml
├── README.md
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── backup-pv.yaml
│   ├── backup-pvc.yaml
│   ├── backup-secret.yaml
│   ├── configmap.yaml
│   ├── deployment-statefulset.yaml
│   ├── ingress.yaml *
│   ├── proxy-ks-secret.yaml
│   ├── proxy-route.yaml
│   ├── proxy-svc.yaml
│   ├── pv.yaml
│   ├── pvc.yaml
│   ├── route.yaml
│   ├── secret.yaml
│   ├── service.yaml
│   └── serviceaccount.yaml
├── values.yaml
└── my-values.yaml *

ingress.yamlの編集箇所はspec.rules[].http.paths[].pathを消去するだけです。
デフォルトではpath: /となっていますがこれだとjsファイルを読み込むことができなくなるので除く必要があります。

template/ingress.yaml
{{- if .Values.ingress.enabled -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ template "nexus.fullname" . }}
  labels:
{{ include "nexus.labels" . | indent 4 }}
  annotations:
    {{- range $key, $value := .Values.ingress.annotations }}
    {{ $key }}: {{ $value | quote }}
    {{- end }}
spec:
  rules:
{{- if .Values.nexusProxy.env.nexusHttpHost }}
    - host: {{ .Values.nexusProxy.env.nexusHttpHost }}
      http:
        paths:
          - backend:
            {{- if .Values.nexusProxy.svcName }}
              serviceName: {{ .Values.nexusProxy.svcName }}
            {{- else }}
              serviceName: {{ template "nexus.fullname" . }}
            {{- end }}
{{- if .Values.nexusProxy.enabled }}
              servicePort: {{ .Values.nexusProxy.port }}
{{- else }}
              servicePort: {{ .Values.nexus.nexusPort }}
{{- end }}
{{- end }}
{{- if .Values.nexusProxy.enabled -}}
{{- if .Values.nexusProxy.env.nexusDockerHost }}
    - host: {{ .Values.nexusProxy.env.nexusDockerHost }}
      http:
        paths:
          - backend:
            {{- if .Values.nexusProxy.svcName }}
              serviceName: {{ .Values.nexusProxy.svcName }}
            {{- else }}
              serviceName: {{ template "nexus.fullname" . }}
            {{- end }}
              servicePort: {{ .Values.nexusProxy.port }}
{{- end }}
{{- end -}}
{{- with .Values.ingress.rules  }}
{{ toYaml . | indent 2 }}
  {{- end -}}
{{- if .Values.ingress.tls.enabled }}
  tls:
    - hosts:
      {{- if .Values.nexusProxy.env.nexusHttpHost }}
        - {{ .Values.nexusProxy.env.nexusHttpHost }}
      {{- end }}
      {{- if .Values.nexusProxy.env.nexusDockerHost }}
        - {{ .Values.nexusProxy.env.nexusDockerHost }}
      {{- end }}
      {{- if .Values.ingress.tls.secretName }}
      secretName: {{ .Values.ingress.tls.secretName | quote }}
      {{- end }}
{{- end -}}
{{- end }}

my-values.yamlは下記となります。
すでに述べた通りALB Ingress Controllerとkube2iamがデプロイされていることを前提としていて、PodにはS3FullAccessPolicyが与えられたIAM Roleを付与します。

my-values.yaml
statefulset:
  enabled: true
nexus:
  dockerPort: 5003
  nexusPort: 8081
  service:
    type: NodePort
  podAnnotations:
    iam.amazonaws.com/role: s3-full-access-role
nexusProxy:
  enabled: true
  env:
    nexusDockerHost: registry.sample.com
    nexusHttpHost: nexus.sample.com
ingress:
  enabled: true
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
  tls:
    enabled: false

次のコマンドでnexusをデプロイします。

$ helm install --values my-values.yaml sonatype-nexus ./

あとはアクセスするときに名前解決できるようにRoute53等で設定を加えれば良いです。

リポジトリ作成

Nexusでリポジトリを作成する時にはblob storeを選択する必要があります。
今回はデフォルトで用意されているFILE方式のものを使用します。
このblob storeはEBSにマウントされています。

docker(hosted)とraw(hosted)をリポジトリとして作成していきます。
前者はDockerレジストリ、後者は画像などの格納場所を用途としています。

①docker(hosted)

Repositoryからdocker(hosted)を選択します。

NameとHTTPだけ埋めて作成します。
HTTP PortはNexusデプロイ時にDockerレジストリのために用意したポートを使用します。
ここでは5003です。

問題なく作成されたことを画面で確認します。

②raw(hosted)

Repositoryからraw(hosted)を選択する。

Nameだけ埋めて作成します。

問題なく作成されたことを画面で確認します。

データ格納

Dockerイメージと画像をそれぞれdocker(hosted)、raw(hosted)に格納していきます。

①docker(hosted)

dockerコマンドでDockerイメージをアップロードします。
HTTPの場合はクライアント側にinsecure registryの設定を入れないといけないことに注意しましょう。

$ docker login registry.sample.com
$ docker push registry.sample.com/alpine:3.7

Nexus画面より、問題なくアップロードされていることを確認します。

②raw(hosted)

Nexus画面からraw(hosted)を選択しUpload componentをクリックします。

Browseからローカルの画像を選択しUploadします。

こちらも問題なくアップロードされることを確認します。

データ移行

EBSからS3へのデータ移行手順を説明していきます。

S3バケットの作成

事前にS3バケットを作成しておきます。
Nexusの設定でprefix指定ができるので既存のバケットを使用することも可能です。

$ aws s3 mb s3://sonatype-nexus-blobs

S3へのデータ転送

NexusコンテナにAWS CLIが入っていないのでローカルにコピーしてからS3へデータ転送します。

$ mkdir blobs
$ kubectl cp sonatype-nexus-0:/nexus-data/blobs ./blobs
$ aws s3 cp blobs/ s3://sonatype-nexus-blobs --recursive

NexusのDBの編集

NexusのDBを手動で変更しblobsの保存方式をFILEからS3にしていきます。
Nexusにアクセスできないよう事前にServiceの削除等をしておくことをおすすめします。

## Nexusコンテナ内にプロセスを起動させる
$ kubectl exec sonatype-nexus-0 -it /bin/bash

## NexusのDBに接続する
$ cd /opt/sonatype/nexus
$ java -jar lib/support/nexus-orient-console.jar
> connect plocal:/nexus-data/db/config admin admin

## 保存方式をS3に変更する
> update repository_blobstore set type="S3" where name="default"

## リージョンとS3バケット情報を入れる
> update repository_blobstore set attributes.s3={region: 'ap-northeast-1', bucket: 'sonatype-nexus-blobs', prefix: 'default', expiration: -1}  where name="default"

上記手順を終えたらPodの再起動をします。

$ kubectl delete pod sonatype-nexus-0

確認

Nexus画面でblob storeを確認します。
TypeがS3になっていることが分かります。

Dockerレジストリを確認します。
docker pullできることが分かります。

$  docker pull registry.sample.com/alpine:3.7
3.7: Pulling from alpine
Digest: sha256:ab3fe83c0696e3f565c9b4a734ec309ae9bd0d74c192de4590fd6dc2ef717815
Status: Downloaded newer image for registry.moguta.ml/alpine:3.7

rawリポジトリは画面で確認します。
Pathから画像ファイルを選択します。

別タブで画像が表示されます。

おわりに

EKSにHelmでデプロイしたNexusのblob storeをEBSからS3へ移行させる手順を説明しました。
blob storeの中身が大きいとその分ローカルストレージの容量を確保しないといけないことに注意です。

参考

Nexus Repository Manager 3 Storage Guide
sonatype Nexusのblob store を FileからS3に変更する