ラベル kubernetes の投稿を表示しています。 すべての投稿を表示
ラベル kubernetes の投稿を表示しています。 すべての投稿を表示

2021年6月21日月曜日

k8s では Service を作ればクラスタ内の Pod から簡単にアクセスできるようになる

k8s では Service を作ればクラスタ内の Pod から簡単にアクセスできるようになる

概要

今更ですが備忘録として残しておきます Service 名でアクセスできるのが嬉しい点かなと思います

環境

  • k8s v1.20.1

マニフェスト

  • vim deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx:latest
        volumeMounts:
        - name: postgres-password
          mountPath: "/tmp"
          readOnly: true
        ports:
        - containerPort: 80
      volumes:
      - name: postgres-password
        secret:
          secretName: postgres.acid-gitlab.credentials.postgresql.acid.zalan.do

---

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx

動作確認

  • kubectl run curl --image=radial/busyboxplus:curl -i --tty
  • cur my-nginx

最後に

あくまでも同一クラスタ内でのみ可能なので注意してください

2021年6月17日木曜日

k8s の kustomize に入門する

k8s の kustomize に入門する

概要

kustomize は k8s のマニフェストを生成、管理することができるツールです helm や helmfile に近いツールですが kubectl に標準で搭載されているので別途インストール作業は不要で使えます 今回は簡単なリソース作成を kustomize を使ってやってみました

環境

  • k8s 1.20.1
  • kubectl 1.20.4

今回の流れ

configMap で作成した情報を nginx で表示するアプリを作成してみます 最終的には kustomize.yaml で各種リソースを定義してデプロイします

profile.txt の作成

今回は configMap として登録します kustomize では configMap を作成するために configMapGenrator という機能が使えます これはファイルから configMap の定義を生成してくれる機能です

  • vim profile.txt
name=hawksnowlog

この profile.txt を使って configMap を作成するために kustomize.yaml というファイルを作成します

  • vim kustomize.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

configMapGenerator:
- name: user-profile
  files:
  - profile.txt

とりあえずこれでビルドしてみると kustomize が自動生成してくれるマニフェストの状態を確認することができます

  • kubectl kustomize .

こんな感じで kustomize.yaml にいろいろな定義をしていくことで一括でマニフェストを管理してくれるツールになります

deployment.yaml の作成

次に deployment.yaml を作成します 先程定義した configMap を使うように定義します

  • vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: nginx:latest
        volumeMounts:
        - name: profile
          mountPath: /usr/share/nginx/html
      volumes:
      - name: profile
        configMap:
          name: user-profile

単純な deployment の定義になります volumeMounts で configMap を参照できます 今回はテキストファイルですが nginx のドキュメントルートに配置してあとから確認できるようにします

そしてこの deployment.yaml も kustomize.yaml で管理するので追記します 普通のマニフェストを管理する場合は resoureces ディレクティブを使って定義します

  • vim kustomize.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

configMapGenerator:
- name: user-profile
  files:
  - profile.txt

resources:
- deployment.yaml

service.yaml の作成

deploment によってデプロイされた Pods にアクセスするために service を定義します NodePort でアクセスします

  • vim service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: my-app

selector の「app: my-app」は deployment のラベルと合わせるようにしましょう

これも kustomize.yaml に追記します

  • vim kustomize.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

configMapGenerator:
- name: user-profile
  files:
  - profile.txt

resources:
- deployment.yaml
- service.yaml

動作確認

ここまで作成できたら適用してみます kustomize を使っている場合はすべてのリソースを一回でデプロイできます

  • kubectl apply -k .

-f ではなく -k オプションなので注意しましょう

これでデプロイされると以下のように kustomize によりリソースが作成されているのが確認できると思います

  • kubectl get -k .
NAME                                       DATA   AGE
configmap/user-profile-gd9h846t5c   1      3m25s
NAME             TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/my-app   NodePort   10.110.195.120   <none>        80:30722/TCP   11m
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-app   1/1     1            1           23s

あとは NodePort で LISTEN しているポートにアクセスすればちゃんと profile.txt の内容が確認できます

  • curl node_ip:30722/profile.txt

=> name=hawksnowlog

リソース削除

  • kubectl delete -k .

最後に

自分でマニフェストを作成して管理する際にわざわざ helm chart のテンプレートとして書きたくない場合には kustomize を使う感じかなと思います

helmfile もあるのを考えると helm に寄せるほうが良い気はしますが一概にどちらが良いかは何とも言えないかなと思います

kubectl でのオペレーションに慣れている人は kustomize にしたほうがいいし helm でのオペレーションに慣れている人は helm にしたほうがいいなどはあるかなと思います

参考サイト

2021年6月14日月曜日

bitnami の PostgreSQL-ha helm chart で好きなユーザを追加する方法

bitnami の PostgreSQL-ha helm chart で好きなユーザを追加する方法

概要

初期化スクリプトを使って実現します また HA 構成の場合は pgpool 側にも認証情報の追加が必要なのもポイントです pgpool 側にもユーザを追加するための初期化スクリプトを流します

環境

  • kubernetes 1.20.5
  • helm 3.5.2
  • bitnami PostgreSQL ha helm chart 7.6.2

values.yaml

postgresql:
  password: xxxx
  repmgrPassword: xxxx
  initdbScripts:
      setup.sql: |
        CREATE USER user1 WITH PASSWORD 'xxxx';
        CREATE USER user2 WITH PASSWORD 'xxxx';
        CREATE DATABASE db1 WITH OWNER user1;
        CREATE DATABASE db2 WITH OWNER user2;

pgpool:
  adminPassword: xxxx
  initdbScripts:
      setup.sh: |
        #!/bin/bash
        USERS=("uesr1:xxxx" "user2:xxxx")
        for user in "${USERS[@]}"; do
            user_info=(${user//:/ })
            pg_md5 -m --config-file="/opt/bitnami/pgpool/conf/pgpool.conf" -u "${user_info[0]}" "${user_info[1]}"
        done

service:
  type: NodePort
  nodePort: 30432

少し解説

好きなユーザを追加したい場合は postgresql.username があるのですがこれは使わないようにしましょう 基本的には initdbScripts に SQL やシェルスクリプトを書いて追加します

まず posgresql 側には CREATE USER コマンドを発行してユーザを作成します このときパスワードも指定します

次に pgpool 側です こちらは pg_md5 コマンドを使って /opt/bitnami/pgpool/conf/pool_passwd に認証情報を追加する必要があります HA 構成の場合認証箇所が postgresql と pgpool の 2 箇所になるのでそれぞれに認証情報を登録する必要があります pgpool Pod が起動後に手動で追加しても OK です

あとは SQL などで好きなコマンドを発行して上げれば OK です postgresql.username を指定しないことでデフォルトの postgres ユーザを使ってコマンドを発行してくれるので権限の強いコマンドでも実行できるようになっています

参考サイト

2021年6月12日土曜日

k8s で PostgreSQL Operator を試してみた (Zalando編)

k8s で PostgreSQL Operator を試してみた (Zalando編)

概要

PostgreSQL Operator は Postgres を k8s 上で簡単に構築/運用するための CustomResource を使ったオーケストレーションツールです 今回は PostgreSQL Operator を使って Postgres の構築を行ってみました

環境

  • k8s v1.20.1
  • helm v3.5.2
  • PostgreSQL Operator 1.6.3

PostgreSQL Operator のデプロイ

helm を使うと簡単です kustomize やマニフェストからデプロイする方法もありますが今回は helm を使います

最新版が Artifacthub で公開されてはいないので Github から直接チャートを展開します 以下のように Operator が展開されれば OK です まだこの時点では PostgreSQL サーバ自体はありません

NAME                                READY   STATUS    RESTARTS   AGE
postgres-operator-88f7975df-tgf77   1/1     Running   0          85s

PostgreSQL Operator UI のデプロイ

Operator には管理用の UI があり PostgreSQL の構築や管理を UI から行うことができます

  • helm install postgres-operator-ui ./charts/postgres-operator-ui

Pod がデプロイできれば OK です

デフォルトだと外部からアクセスできないようになっているので Service を編集して NodePort に変更します

  • kubectl edit svc postgres-operator-ui
type: NodePort

Service の NodePort は適宜変更してください

http://node_ip:30595/#new

で Operator の管理 UI にアクセスできます

PostgreSQL サーバの構築

管理 UI から行ってみます 先程の URL にアクセスすると PostgreSQL を作成するためのフォームが表示されます

Name や Users など好きな情報を入力して作成しましょう なお後で紹介しますが Operator 経由の PostgreSQL の構築では好きなユーザは作成できますが好きなユーザに好きなパスワードを設定することはできません 基本的には Operator が自動で生成します

作成中になるとステータスもちゃんと表示されています 完了するまで待ちましょう

作成が完了すると以下のように PostgreSQL が作成されます

  • kubectl get all -l team=acid
NAME              READY   STATUS    RESTARTS   AGE
pod/acid-test-0   1/1     Running   0          12m

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/acid-test        ClusterIP   10.107.79.204   <none>        5432/TCP   12m
service/acid-test-repl   ClusterIP   10.107.39.37    <none>        5432/TCP   12m

NAME                         READY   AGE
statefulset.apps/acid-test   1/1     12m

NAME                                 TEAM   VERSION   PODS   VOLUME   CPU-REQUEST   MEMORY-REQUEST   AGE   STATUS
postgresql.acid.zalan.do/acid-test   acid   13        1      10Gi     100m          100Mi            12m   Running

構成を変更して NodePort からアクセスできるようにしてみる

デプロイした PostgreSQL の構成も管理 UI から変更できます

作成したクラスタの「Edit」を選択すると以下のような編集画面になります

外部からアクセスできるようにするためには「enableConnectionPooler」「enableMasterLoadBalancer」「enableReplicaLoadBalancer」を true にします

下にある「Apply」をクリックすれば PostgreSQL クラスタの再構築が行われます 完了すると以下のように外部からアクセスできるようになっています

  • kubectl get svc -l team=acid
NAME             TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
acid-test        LoadBalancer   10.107.79.204   <pending>     5432:31815/TCP   18m
acid-test-repl   LoadBalancer   10.107.39.37    <pending>     5432:30569/TCP   18m

アクセスする

パスワードはシークレットから取得します あとは公開したノードの IP とポートを使って postgres ユーザでアクセスできるか確認してみましょう

基本的な使い方はこんな感じです 今回は UI でデプロイしましたがマニフェストも UI が自動生成してくれるのでマニフェストでデプロイしたい場合でも簡単です

おまけ: ユーザの好きなパスワードは設定できない

過去に紹介した bitnami の PostgreSQL helm chart を使うとユーザのパスワードを設定できます Operator でもできないかなと思い色々試したのですがダメでした 一応試した方法を紹介します (参考)

やった方法としては

  • secret を事前に登録
  • マニフェストでユーザのロールを指定

です

  • vim secret.yaml
apiVersion: v1
data:
  password: YXNkZmdoamtsCg==
  username: cHJhZWZlY3Q=
kind: Secret
metadata:
  labels:
    application: spilo
    cluster-name: acid-gitlab
    team: acid
  name: praefect.acid-gitlab.credentials.postgresql.acid.zalan.do
  namespace: default
type: Opaque

kubectl apply -f ./secret.yaml

マニフェストをデプロイすると Operator 自動で secret を作成してしまうので事前に登録しておきました

そしてその後で Operator を使ってマニフェストからデプロイします

  • vim postgres.yaml
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  labels:
    team: acid
  name: acid-gitlab
  namespace: default
spec:
  allowedSourceRanges: null
  databases:
    praefect: praefect
  enableConnectionPooler: true
  enableMasterLoadBalancer: true
  enableReplicaLoadBalancer: true
  numberOfInstances: 1
  postgresql:
    version: '13'
  resources:
    limits:
      cpu: 500m
      memory: 500Mi
    requests:
      cpu: 100m
      memory: 100Mi
  teamId: acid
  users:
    praefect:
    - superuser
    - login
    - createrole
    - createdb
  volume:
    size: 10Gi
  • kubectl apply -f ./postgres.yaml

これで事前に作成した secret のパスワードを使って psql コマンドでログインしようとしてみましたがダメでした

あくまでも secret は外部からパスワードを確認する方法のようで PostgreSQL の内部では自動生成されたパスワードを使ってユーザの作成が行われているようです

最後に

バックアップやバージョンアップも簡単にできるので簡易 RDS みたいに使えます

UI があるのはかなり便利かなと思います

参考サイト

2021年6月9日水曜日

helmfile 超入門

helmfile 超入門

概要

helmfile は helm の values.yaml やパラメータ、バージョン情報などを YAML ファイルで宣言的に管理できるツールです 今回はインストール方法と簡単な使い方を紹介します

環境

  • Ubuntu 18.04
  • helm v3.5.2
  • helmfile 0.139.7

helmfile のインストール

まずは helmfile コマンドをインストールします 少しややこしいですが helmfile はコマンド名にもなっています

バイナリを 1 配置するだけで完了です docker でも動作させることができますが今回はバイナリインストールを採用します

helmfile version v0.139.7

helm diff プラグインのインストール

helmfile の一部のコマンドが helm-diff に依存しているのでインストールしておきましょう

helmfile.yaml を作成する

では helmfile.yaml を作成しましょう 本来 helm コマンドの引数になる情報を YAML ファイルに記載する感じになります

  • vim helmfile.yaml
releases:
- name: request-dumper
  namespace: default
  chart: request-dumper/request-dumper
  version: 0.1.1
  set:
  - name: replicaCount
    value: 2

helm を実行したことがあるのであればそれぞれのパラメータが何を意味しているのか何となくわかると思います

コマンドで指定していたものがファイルに定義できているのが確認できると思います

動作確認

では実行してみましょう デプロイするには apply サブコマンドを使います

  • helmfile apply

すると helmfile に記載された chart がデプロイされると思います 削除される場合は destroy サブコマンドを使います

  • helmfile destroy

values.yaml を使う方法

set ではなく values を使えば OK です

releases:
- name: gitlab
  namespace: gitlab
  chart: gitlab/gitlab
  values:
  - ./values.yaml

これで既存の values.yaml ファイルをそのまま使うことができます

helmfile sync について

デプロイするサブコマンドは apply の他 sync というサブコマンドがあります 大きく違いは以下の通りです

  • apply・・・マニフェストに差分がある場合に helm upgrade を実行する
  • sync・・・毎回 upgrade を実行するので差分がなくても revision が上がっていく

という感じの違いがあります 基本は apply を使うのが良いかなと思います

最後に

今回は簡単な方法だけ紹介しているので他にもいろいろな定義をすることができます

例えば他にも helmfile.yaml を定義してそれを include して一気にデプロイすることもできます

使用する helm が増えてきた場合にはかなり強力ツールになるかなと思います

参考サイト

2021年6月6日日曜日

k8s の Operator を理解するために Operator SDK golang をとりあえず流してみた

k8s の Operator を理解するために Operator SDK golang をとりあえず流してみた

概要

k8s の Operator や CustomResource の実装をするにあたって全くイメージがなかったのでまずは Operatro SDK のチュートリアルを試してみました

環境

  • k8s v1.20.1
  • golang 1.16.3
    • operator-sdk 1.8.0
  • docker 19.03.6

準備

今回は以下の環境で実施しています

  • k8s 環境の準備
  • docker プライベートレジストリの準備

operator-sdk のインストール

まずは operator-sdk をインストールします これをインストールすることでひな形やビルドを簡単に行うことができます

  • export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac)
  • export OS=$(uname | awk ‘{print tolower($0)}’)
  • export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.8.0
  • curl -LO KaTeX parse error: Expected group after '_' at position 35: …L}/operator-sdk_̲{OS}_${ARCH}
  • gpg --keyserver keyserver.ubuntu.com --recv-keys 052996E2A20B5C7E
  • curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt
  • curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt.asc
  • gpg -u “Operator SDK (release) cncf-operator-sdk@cncf.io” --verify checksums.txt.asc
  • grep operator-sdk_KaTeX parse error: Expected group after '_' at position 5: {OS}_̲{ARCH} checksums.txt | sha256sum -c -

これで operator-sdk コマンドが使えるようになります

  • operator-sdk version

プロジェクトの作成

プロジェクトの雛形を作成します

example.com の部分は自身で準備したプライベートレジストリのドメインを設定してください

example.com でも問題なく進められるのでこのままでも OK です

以下のようなディレクトリとファイル構成で作成されます

  • tree
.
├── config
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   └── manager_config_patch.yaml
│   ├── manager
│   │   ├── controller_manager_config.yaml
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── manifests
│   │   └── kustomization.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── role_binding.yaml
│   │   └── service_account.yaml
│   └── scorecard
│       ├── bases
│       │   └── config.yaml
│       ├── kustomization.yaml
│       └── patches
│           ├── basic.config.yaml
│           └── olm.config.yaml
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT

API リソースの作成

次に operator の動作に必要な API の go ファイルを作成します 生成される go ファイルでプログラムすることで独自のオペレータを作成することができます

今回はチュートリアルなので github にあるサンプルを使います なお公式のチュートリアルだけだとすべてが記載されていないので注意してください

CustomResource の定義

こちらは spec のパラメータなどを指定します

コントローラの定義

実際にメインの処理を記載するコントローラを生成します

なお公式のチュートリアルは執筆時点では v1.3.0 タグの mmemcached_controller.go を使っているのですがそれで実行すると 60 行目で invalid memory address or nil pointer dereference になります

リソースファイルの生成

memcached_types.go と memcached_controller.go を編集できたらリソースファイルを生成します

  • make generate
  • make manifests

成功すると CustomResource と RBAC のマニフェストファイルが生成されます

  • less config/crd/bases/cache.example.com_memcacheds.yaml
  • less config/rbac/role.yaml

依存関係でエラーになる場合は以下を追加でインストールしてください

ビルド&プッシュ

実際に k8s 上に CustomResource をデプロイするためにイメージをビルドしてレジストリにプッシュします

冒頭プロジェクト作成時に指定した domain の部分をレジストリのドメインにしていてもプッシュ先の URL が違う場合は Makefile を修正します IMG の部分がビルドされるイメージ名になるのでここにプッシュ可能なイメージ名を指定します

  • vim Makefile
IMG ?= container-registry.your.private.repo/hawksnowlog/proj:latest

ちなみにデフォルトでは dockerhub にプッシュするようになっています あとはビルド、プッシュしましょう

  • make docker-build docker-push

もしプッシュできない場合は上記の IMG の設定を再確認してください もしくはプライベートレジストリにログインできているか確認してください もしできていない場合は docker login してからビルドしてください

デプロイ

CustomResource のイメージがレジストリにプッシュできたら実際に k8s 上に展開してみます

  • make deploy

しばらくすると以下のように CustomResource 用の Pod がデプロイされます

  • kubectl get pod -n memcached-operator-system
NAME                                                    READY   STATUS    RESTARTS   AGE
memcached-operator-controller-manager-6fb5b6d8b-bg4x5   2/2     Running   0          8m40s

認証ありのプライベートレジストリを使っている場合は

k8s からもプライベートレジストリにアクセスできる必要があります レジストリ認証情報を secret として登録しその secret 情報を CustomResource 用の Pod から使うようにします

  • kubectl create secret generic regcred --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson -n memcached-operator-system
  • kubectl edit deployment -n memcached-operator-system
    spec:
      imagePullSecrets:
      - name: regcred

もしかすると operator 作成時に imagePullSecrets を指定する方法があるのですが見つからなかったので今回は make deploy 後に手動で secrts の情報を指定しています

動作確認

これで自作の CustomResource を使ったオペレータを使って Pod などのデプロイができるようになります マニフェストは以下のファイルにあります spec の部分に size: 3 を指定しましょう

  • vim config/samples/cache_v1alpha1_memcached.yaml
apiVersion: cache.example.com/v1alpha1
kind: Memcached
metadata:
  name: memcached-sample
spec:
  size: 3

ポイントは kind: Memcached になっている点です これが CustomResource として自作で作成したリソースになります

デプロイして memcached の Pod が上がってくることを確認します

  • kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
# kubectl get pod
NAME                                               READY   STATUS    RESTARTS   AGE
memcached-sample-6c765df685-gsc5w                  1/1     Running   0          21s
memcached-sample-6c765df685-r9dnh                  1/1     Running   0          21s
memcached-sample-6c765df685-v8tph                  1/1     Running   0          21s
# kubectl exec pod/memcached-sample-6c765df685-gsc5w -it -- telnet localhost 11211
set name 0 0 11
hawksnowlog
STORED
quit
Connection closed by foreign host
command terminated with exit code 1

# kubectl exec pod/memcached-sample-6c765df685-gsc5w -it -- telnet localhost 11211
get name
VALUE name 0 11
hawksnowlog
END
quit
Connection closed by foreign host
command terminated with exit code 1

今回は Service などの定義がないので直接 Pod で実行していますが問題なく memcached が動作するのが確認できると思います

クリーンアップ

  • make undeploy

最後に

ポイントは

  • CustomResource を作成し API として k8s 上にデプロイする
  • その API を使って CustomResource を作成する
  • リソース作成時に好きな命令を golang で実装できる

です とりあえず今回のチュートリアルだけでもこの流れはつかめるかなと思います

実際は controller や types をプログラムして独自のオペレータを実装することになります ビルドやデプロイの流れは同じかなと思います

トラブルシューティング

memcached の Pod が CustomResource を使ってデプロイできない場合は memcached-operator-controller-manager のログを確認してみましょう

go スクリプトのビルドはできたけど nil 参照などしている場所がある場合はそこでエラーとなり CustomResource が動作していないことが確認できると思います

参考サイト

2021年5月4日火曜日

bitnami の PostgreSQL helm chart を使ってみた

bitnami の PostgreSQL helm chart を使ってみた

概要

PostgreSQL の helm chart を使う場合は bitnami が公開している helm chart が便利です
今回は k8s 上にデプロイする方法と HA 構成を試してみました

環境

  • kubernetes 1.20.4
  • helm 3.5.2
  • bitnami PostgreSQL helm chart 10.3.18

リポジトリインストール

  • helm repo add bitnami https://charts.bitnami.com/bitnami
  • helm repo update

とりあえずデプロイ

  • helm install test bitnami/postgresql

NodePort でアクセスできるようにする

  • export POSTGRES_PASSWORD=$(kubectl get secret --namespace "default" test-postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode)
  • helm upgrade test bitnami/postgresql --set service.type=NodePort --set service.nodePort=30432 --set postgresqlPassword=$POSTGRES_PASSWORD

デプロイできたか確認しましょう

  • kubectl get pod,svc
NAME                                                   READY   STATUS    RESTARTS   AGE
pod/nfs-subdir-external-provisioner-78cc5b4979-tnnnj   1/1     Running   0          21d
pod/test-postgresql-0                                  1/1     Running   0          8m11s

NAME                               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/kubernetes                 ClusterIP   10.96.0.1        <none>        443/TCP          21d
service/test-postgresql            NodePort    10.100.235.141   <none>        5432:30432/TCP   8m11s
service/test-postgresql-headless   ClusterIP   None             <none>        5432/TCP         8m11s

動作確認

  • apt -y install postgresql-client
  • export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") PGPASSWORD="$POSTGRES_PASSWORD" psql --host $NODE_IP --port 30432 -U postgres -d postgres

これでアクセスできれば OK です
あとはテーブルを作成たりデータをインサートすれば OK です

HA 構成をデプロイする

bitnami/postgresql-ha チャートを使います
とりあえずデプロイしてみましょう

  • helm install test2 bitnami/postgresql-ha

NodePort でアクセスできるようにする

HA 構成も NodePort 経由でアクセスできるようにします

  • export POSTGRES_PASSWORD=$(kubectl get secret --namespace default test2-postgresql-ha-postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode)
  • helm upgrade test2 bitnami/postgresql-ha --set service.type=NodePort --set service.nodePort=30432 --set postgresqlPassword=$POSTGRES_PASSWORD

起動したか確認します

  • kubectl get pod,svc
NAME                                                   READY   STATUS    RESTARTS   AGE
pod/nfs-subdir-external-provisioner-78cc5b4979-tnnnj   1/1     Running   0          21d
pod/test2-postgresql-ha-pgpool-75cd676457-2gx44        1/1     Running   0          19m
pod/test2-postgresql-ha-postgresql-0                   1/1     Running   0          19m
pod/test2-postgresql-ha-postgresql-1                   1/1     Running   0          19m
NAME                                              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/kubernetes                                ClusterIP   10.96.0.1       <none>        443/TCP          21d
service/test2-postgresql-ha-pgpool                NodePort    10.99.241.206   <none>        5432:30432/TCP   19m
service/test2-postgresql-ha-postgresql            ClusterIP   10.98.87.23     <none>        5432/TCP         19m
service/test2-postgresql-ha-postgresql-headless   ClusterIP   None            <none>        5432/TCP         19m

動作確認

psql でアクセスする方法はシングル構成のときと同じです

  • export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  • PGPASSWORD="$POSTGRES_PASSWORD" psql -h $NODE_IP -p 30432 -U postgres -d postgres

また HA の状態を確認してみます

  • kubectl exec pod/test2-postgresql-ha-postgresql-0 -- /opt/bitnami/scripts/postgresql-repmgr/entrypoint.sh repmgr -f /opt/bitnami/repmgr/conf/repmgr.conf service status
postgresql-repmgr 08:21:12.78
postgresql-repmgr 08:21:12.78 Welcome to the Bitnami postgresql-repmgr container
postgresql-repmgr 08:21:12.78 Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-postgresql-repmgr
postgresql-repmgr 08:21:12.79 Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-postgresql-repmgr/issues
postgresql-repmgr 08:21:12.79
 ID | Name                             | Role    | Status    | Upstream                         | repmgrd | PID | Paused? | Upstream last seen
----+----------------------------------+---------+-----------+----------------------------------+---------+-----+---------+--------------------
 1000 | test2-postgresql-ha-postgresql-0 | primary | * running |                                  | running | 1   | no      | n/a
 1001 | test2-postgresql-ha-postgresql-1 | standby |   running | test2-postgresql-ha-postgresql-0 | running | 1   | no      | 1 second(s) ago

ちゃんと HA 構成になっているのが確認できると思います

参考サイト

2021年5月2日日曜日

bitnami の redis helm chart を使ってみた

bitnami の redis helm chart を使ってみた

概要

bitnami の redis helm chart を使ってみました
いくつかのデプロイ方式があるのでそれぞれ試しています

環境

  • kubernetes 1.20.4
  • helm 3.5.2
  • bitnami redis helm chart 14.0.1

事前準備

何でもいいので pv を用意しましょう
local を使う方法はこちら
default の storageClass を用意しても OK です
nfs で default の storageClass を作成する方法はこちら

リポジトリインストール

  • helm repo add bitnami https://charts.bitnami.com/bitnami
  • helm repo update

初期デプロイ

  • helm install test bitnami/redis

これで secret もデプロイされるのでこのパスワードを使って redis の構成を変更していきます

パスワードは環境変数に設定しておきます

  • export REDIS_PASSWORD=$(kubectl get secret --namespace default test-redis -o jsonpath="{.data.redis-password}" | base64 --decode)

Master-Slave 構成をデプロイする

まずは Master-Slave 構成を試してみます
アクセスするのは NodePort を使います

  • helm upgrade test bitnami/redis --set master.service.type=NodePort --set master.service.nodePort=30700 --set replica.service.type=NodePort --set replica.service.nodePort=30800 --set auth.password=$REDIS_PASSWORD

Master へのアクセスは 30700 ポートを使い Slave へのアクセスは 30800 を使います

デプロイした起動しているか確認しましょう
Master が 1 つ Slave が 3 つ起動していれば OK です

  • kubectl get pod
NAME                                               READY   STATUS    RESTARTS   AGE
nfs-subdir-external-provisioner-78cc5b4979-tnnnj   1/1     Running   0          19d
test-redis-master-0                                1/1     Running   0          97s
test-redis-replicas-0                              1/1     Running   0          7s
test-redis-replicas-1                              1/1     Running   0          48s
test-redis-replicas-2                              1/1     Running   0          68s
  • kubectl get svc
NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes            ClusterIP   10.96.0.1       <none>        443/TCP          19d
test-redis-headless   ClusterIP   None            <none>        6379/TCP         6m45s
test-redis-master     NodePort    10.97.246.247   <none>        6379:30700/TCP   6m45s
test-redis-replicas   NodePort    10.105.78.89    <none>        6379:30800/TCP   6m45s

動作確認

redis-cli を使って動作確認してみましょう
まずは Master にアクセスしてみます
ちゃんと Wirte できることが確認できます

  • export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  • redis-cli -h $NODE_IP -p 30700 -a $REDIS_PASSWORD
NODE_IP:30700> set name hawksnowlog
OK

次に Slave にアクセスします

  • redis-cli -h $NODE_IP -p 30800 -a $REDIS_PASSWORD

Slave では Write できないのが確認できます
また Master で set した値がちゃんと参照できるのが確認できます

NODE_IP:30800> set age 10
(error) READONLY You can't write against a read only replica.
NODE_IP:30800> get name
"hawksnowlog"

failover を試してみる

基本は failover せず StatefullSet によって Pod が復帰してくる感じになります

  • kubectl delete pod test-redis-master-0

で Master を削除すると再度上がってきます
再起動中は Master にアクセスできなくなります

Sentinel 構成をデプロイしてみる

次に Sentinel 構成をデプロイしてみます

  • helm install test-sentinel bitnami/redis --set auth.password=$REDIS_PASSWORD --set sentinel.enabled=true --set sentinel.service.type=NodePort --set sentinel.service.nodePorts.redis=30700 --set sentinel.service.nodePorts.sentinel=30800

Redis へのアクセスは 30700 ポートを使い Sentinel へのアクセスは 30800 を使います

Sentinel への書き込みや読み込みはできないので基本的には 30700 番を使うことになります

動作確認

  • export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  • redis-cli -h $NODE_IP -p 30700 -a $REDIS_PASSWORD

で書き込みと読み込むができることを確認しましょう
また Sentinel では get/set ができないことも確認します

# redis-cli -h $NODE_IP -p 30700 -a $REDIS_PASSWORD
NODE_IP:30700> set name hawksnowlog
OK
NODE_IP:30700> exit
# redis-cli -h $NODE_IP -p 30800 -a $REDIS_PASSWORD
NODE_IP:30800> get name
(error) ERR unknown command `get`, with args beginning with: `name`,

また注意点として Redis の構成は Master-Slave 構成になっています
何度か繰り返すとわかりますが 30700 番にアクセスして set するとできるときとできないときがあるのがわかると思います
これは NodePort 経由で Redis クラスタにアクセスした際にアクセスする Pod はバランシングされているためそうなります
本来であれば常に Master にアクセスしたり常に Slave にアクセスすることになると思います
その場合は Sentinel で現在の Master を調べてその Master にアクセスするようにしましょう

# redis-cli -h $NODE_IP -p 30800 -a $REDIS_PASSWORD
NODE_IP:30800> sentinel get-master-addr-by-name mymaster
1) "10.233.2.232"
2) "6379"
NODE_IP:30800> exit

# kubectl exec --stdin --tty test-sentinel-redis-node-0 -- redis-cli -h 10.233.2.232 -p 6379 -a $REDIS_PASSWORD
Defaulting container name to redis.
Use 'kubectl describe pod/test-sentinel-redis-node-0 -n default' to see all of the containers in this pod.
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.233.2.232:6379> set age 10
OK

failover を試してみる

Sentinel があるので Master の Redis がダウンした場合には Slave が昇格して Master が変わるはずです
Bitnami の Redis Pod の構成の場合 Sentinel + Redis ノードのサイドカー構成で 1 Pod になっているので Pod 内の Redis コンテナのみを削除することで failover を発生させてみます

  • kubectl exec test-sentinel-redis-node-0 -c redis -- /bin/sh -c "kill 1"

これで redis コンテナのみ再起動します
しばらくて redis コンテナが起動したら Master が切り替わっていることを確認してみます

まずはそれぞれの Pod にアクセスして role の情報を確認してみます

# kubectl exec test-sentinel-redis-node-0 -c redis -- redis-cli -a $REDIS_PASSWORD info | grep role
role:slave

# kubectl exec test-sentinel-redis-node-1 -c redis -- redis-cli -a $REDIS_PASSWORD info | grep role
role:master

# kubectl exec test-sentinel-redis-node-2 -c redis -- redis-cli -a $REDIS_PASSWORD info | grep role
role:slave

先程は test-sentinel-redis-node-0 が Master だったのに対して test-sentinel-redis-node-1 に failover していることが確認できます

次に Sentinel にも Master 情報を確認してみましょう

# redis-cli -h $NODE_IP -p 30800 -a $REDIS_PASSWORD
NODE_IP:30800> sentinel get-master-addr-by-name mymaster
1) "10.233.1.200"
2) "6379"

ちゃんと failover しているのが確認できると思います
Master にアクセスして Write できるかも確認してみましょう

ubectl exec --stdin --tty test-sentinel-redis-node-0 -- redis-cli -h 10.233.1.200 -p 6379 -a $REDIS_PASSWORD
Defaulting container name to redis.
Use 'kubectl describe pod/test-sentinel-redis-node-0 -n default' to see all of the containers in this pod.
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.233.1.200:6379> set age 10
OK

問題なさそうです

おまけ: リソース削除

helm uninstall test

for i in `kubectl get pvc -o json | jq -r '.items[].metadata.name'`; do kubectl delete pvc $i; done

最後に

簡単に Sentinel 構成もデプロイできるのでかなり使えそうです
values はある程度理解して使えるようにならないとダメかもしれません

failover させる際に Master の Sentinel も一緒に削除すると Sentinel Cluster が壊れて Pod が上がってこなくなりました
具体的には以下のコマンドで failover のテストをすると Pod が上がってこないのが確認できると思います

  • kubectl delete pod test-sentinel-redis-node-0

ちなみに Slave の Pod を削除してもクラスタは元の状態に戻ります
ダメそうなのは Master の Pod が削除された場合のみのようです

参考サイト

2021年5月1日土曜日

Promethues を helm chart で構築してみた

Promethues を helm chart で構築してみた

概要

Promethues を helm を使ってインストールしてみました

環境

  • kubernetes 1.20.4
  • helm 3.5.2
  • Grafana helm chart 13.8.0

事前準備

何でもいいので pv を用意しましょう
local を使う方法はこちら
default の storageClass を用意しても OK です
nfs で default の storageClass を作成する方法はこちら

リポジトリインストール

  • helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
  • helm repo add kube-state-metrics https://kubernetes.github.io/kube-state-metrics
  • helm repo update

とりあえず使ってみる

  • helm install promethues prometheus-community/prometheus
  • kubectl get pod
NAME                                                  READY   STATUS    RESTARTS   AGE
nfs-subdir-external-provisioner-78cc5b4979-tnnnj      1/1     Running   0          17d
promethues-kube-state-metrics-55c795cd7f-mgg9b        1/1     Running   0          19m
promethues-prometheus-alertmanager-6b68776f64-7xlcq   2/2     Running   0          19m
promethues-prometheus-node-exporter-65j44             1/1     Running   0          19m
promethues-prometheus-node-exporter-j8hx8             1/1     Running   0          19m
promethues-prometheus-node-exporter-wb9bf             1/1     Running   0          19m
promethues-prometheus-pushgateway-844488b78d-k72vt    1/1     Running   0          19m
promethues-prometheus-server-d47764bc7-s5zjv          2/2     Running   0          19m

デフォルトだと nodeexporter や pushgateway, alertmanager なども同時にインストールされるようです
nodeexporter は各ノードにインストールされます

NodePort でアクセスできるようにする

公式のヘルプだと port-forward を使ってローカルからアクセスする方法が表示されます
それだといろいろと面倒なので NodePort でアクセスできるようにします

  • helm upgrade promethues prometheus-community/prometheus --set server.service.type=NodePort --set server.service.nodePort=32090
  • kubectl get svc
NAME                                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes                            ClusterIP   10.96.0.1        <none>        443/TCP        17d
promethues-kube-state-metrics         ClusterIP   10.97.206.173    <none>        8080/TCP       26m
promethues-prometheus-alertmanager    ClusterIP   10.106.111.197   <none>        80/TCP         26m
promethues-prometheus-node-exporter   ClusterIP   None             <none>        9100/TCP       26m
promethues-prometheus-pushgateway     ClusterIP   10.98.175.145    <none>        9091/TCP       26m
promethues-prometheus-server          NodePort    10.110.171.176   <none>        80:32090/TCP   26m

これで http://node:32090 で Prometheus サーバにアクセスできます

監視先を追加する方法

extraScrapeConfigs という values が用意されているのでこれを使います
scrape_configs を直接変更することもできますがデフォルトの k8s の管理 Pod の監視設定などを上書きしてしまうので、extraScrapeConfigs で追記するようにしましょう

- job_name: site_exporter
  scheme: https
  metrics_path: /metrics
  static_configs:
  - targets:
    - kaka-request-dumper.herokuapp.com
  • helm upgrade promethues prometheus-community/prometheus --set rbac.create=true --set server.service.type=NodePort --set server.service.nodePort=32090 --set-file extraScrapeConfigs=my_values.yml

設定がうまく反映されていないようであれば Pod を再起動しましょう

  • kubectl rollout restart deploy promethues-prometheus-server

おまけ: values の取得

  • helm get values promethues -a > promethues_values.yml

参考サイト

2021年4月30日金曜日

Grafana を helm chart で構築してみた

Grafana を helm chart で構築してみた

環境

Grafana を helm chart で k8s 上に構築してみました
アクセスには NodePort を使います

環境

  • kubernetes 1.20.4
  • helm 3.5.2
  • Grafana helm chart 6.7.4

Grafana の helm repo の インストール

  • helm repo add grafana https://grafana.github.io/helm-charts
  • helm repo update

普通に使う

まずは普通に使います
構築して NodePort でアクセスしてみます

  • helm install my-release grafana/grafana --set service.type=NodePort
  • kubectl get svc
AME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE  
kubernetes           ClusterIP   10.96.0.1        <none>        443/TCP        14d  
my-release-grafana   NodePort    10.107.144.202   <none>        80:32483/TCP   8m45s

grafana の Pod がデプロイされたノードの IP を調べます
そして http://node-ip:32483 にアクセスすると Grafana の UI が表示されることが確認できます

ログインする

admin ユーザにでログインします
パスワードは secret に登録されているので以下のコマンドで取得できます

  • kubectl get secret --namespace default my-release-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

ingress 経由で使う

よくあるケースは ingress 経由で使う場合です
ポイントは ingress.hosts と ingress.path で宛先を設定する点です
またサブディレクトリでアクセスしたい場合は serve_from_sub_path を使います

  • vim values.yml
grafana.ini:  
  server:  
    protocol: http  
    domain: localhost  
    root_url: "%(protocol)s://%(domain)s:3000/-/grafana"  
    serve_from_sub_path: true  
ingress:  
  enabled: true  
  hosts:  
    - "grafana.example.com"  
  path: "/-/grafana"  
service:  
  type: NodePort  
  nodePort: 32080

set だと長くなるなるので設定は values.yml を使っています

デプロイしてみましょう

  • helm install my-release grafana/grafana -f values.yml

これで http://node-ip:32080 にアクセスすれば Grafana にアクセスできます
ログイン方法は先程紹介したとおりです

最後に

ログインでリダイレクトされる場合は cookies を削除しましょう

参考サイト

2021年4月12日月曜日

k8s ingress-nginx で hostNetwork を使えば 80 or 443 で LISTEN することができる

k8s ingress-nginx で hostNetwork を使えば 80 or 443 で LISTEN することができる

概要

過去 に ingress-nginx を helm を使ってデプロイする方法を紹介しました
hostNetwork についても少し触れていたのですが改めて動作確認してみました
またこのやり方はテスト環境などクラウドロードバランサを用意できない場合に使いましょう
プロダクションなどでは採用しないようが良いです

環境

  • k8s 1.20.1
  • ingress-nginx chart 3.26.0

ingress-nginx controller のデプロイ

オプションで hostNetwork をオンにします
またその際にデプロイするモードを Damonset にする必要があります

  • helm install hostnetwork-test-ingress ingress-nginx/ingress-nginx --set controller.hostNetwork=true --set controller.service.type="" --set controller.kind=DaemonSet

これで各ノードに ingress-nginx controller がデプロイされ各ノードで 80/443 が LISTEN されます

動作確認

適当に Web アプリをデプロイし Ingress を作成して Ingress 経由でアプリにアクセスできるか確認してみましょう

  • helm install request-dumper request-dumper/request-dumper
  • kubectl get svc request-dumper
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE  
request-dumper NodePort 10.104.206.212 <none> 8080:31036/TCP 16m

8080 ポートに Ingress で接続するように Ingress を作成します

  • vim ingress.yml
apiVersion: networking.k8s.io/v1beta1  
kind: Ingress  
metadata:  
  name: hostnetwork-test-ingress  
  annotations:  
    kubernetes.io/ingress.class: "nginx"  
spec:  
  rules:  
    - host: foo.bar.com  
      http:  
        paths:  
          - path: /  
            backend:  
              serviceName: request-dumper  
              servicePort: 8080
  • kubectl apply -f ingress.yml
  • curl -H "Host: [foo.bar.com](http://foo.bar.com/)" 192.168.100.10

こんな感じでノードの 80 番でアクセスできるのが確認できると思います

最後に

あくまでもテストで使うようにしましょう

参考サイト

2021年4月11日日曜日

nginx-ingress-controller でデプロイするノードを固定する方法

nginx-ingress-controller でデプロイするノードを固定する方法

概要

helm を使って k8s/nginx-ingress-controller をデプロイしている場合に nginx の Pod がデプロイされるホストはデフォルトではランダムで決定します
ノードが複数あり Ingress を NodePort で動作させている場合には Ingress がデプロイされるノードによってアクセスする IP が変わるのでデプロイ先を固定にしたほうが扱いやすい場合があります

環境

  • k8s 1.20.4
  • nginx-ingress-controller 3.26.0

nodeSelector を使う

nginx-ingress-controller の values.yml で nodeSelector が指定できるようになっているのでそれを使うのが一番簡単です
helm install や upgrade 時に以下を指定しましょう

--set controller.nodeSelector."kubernetes\.io/hostname"="node1"

gitlab helm chart で指定する場合には

先頭に更に nginx-ingress を付与します

--set nginx-ingress.controller.nodeSelector."kubernetes\.io/hostname"="node1"

参考サイト

2021年4月10日土曜日

k8s nginx-ingress-controller で NodePort 指定時に http と https ポートを指定する方法

k8s nginx-ingress-controller で NodePort 指定時に http と https ポートを指定する方法

概要

nginx-ingress-controller を helm chart で使用する際に http と https のポートを指定する方法を紹介します
また ingress は type: NodePort で動作させる必要があります

環境

  • k8s 1.20.4

ポートを指定する values を set する

以下の 3 つの値をセットしましょう
helm install or upgrade どちらでも使えます

  • --set nginx-ingress.controller.service.type=NodePort
  • --set nginx-ingress.controller.service.nodePorts.http=32080
  • --set nginx-ingress.controller.service.nodePorts.https=32443

NodPort は 30000-32767 を指定しましょう

参考サイト

2021年4月9日金曜日

Gitlab helm chart でデプロイされた minio にログインする方法

Gitlab helm chart でデプロイされた minio にログインする方法

概要

Gitlab 公式の helm chart ではオブジェクトストレージを使った構成を採用しています
デフォルトでは k8s 上に minio をデプロイしそこに git-lfs などのファイルをアップロードしています
今回は minio にアクセスする方法を紹介します
なお namespace は gitlab にデプロイしているのを想定しています

環境

  • k8s 1.20.4
  • Gitlab 13.10.2

アクセス URL の確認

  • kubectl get ingress -n gitlab

これで minio にアクセスするためのホスト情報が確認できます
DNS の設定などは自身で行ってください
IP でアクセスしたい場合は

  • kubectl get pod -n gitlab -o wide

で gitlab-nginx-ingress-controller がデプロイされているノードを確認します
そして

  • kubectl get node -o wide

で対象のノードの IP を確認し

  • kubectl get svc -n gitlab

で NodePort としてバインドされたポートを確認し IP とポートを使ってアクセスしましょう

シークレットの取得

minio にアクセスするとログイン画面が表示されます
そこでアクセスキーとシークレットキーが必要になるので以下のコマンドで取得しましょう

アクセスキー

  • kubectl get secret -n gitlab gitlab-minio-secret -o jsonpath='{.data.accesskey}' | base64 --decode

シークレットキー

  • kubectl get secret -n gitlab gitlab-minio-secret -o jsonpath='{.data.secretkey}' | base64 --decode

2021年4月8日木曜日

Gitlab Runner を helm を使って k8s 上にデプロイしてみた

Gitlab Runner を helm を使って k8s 上にデプロイしてみた

概要

過去に Gitlab を helm chart を使って k8s 上にインストールしました
今回は Gitlab Runner のみを k8s 上にデプロイしてみました

環境

  • Gitlab 13.10.2
  • k8s 1.20.4

リポジトリのインストール

  • helm repo add gitlab https://charts.gitlab.io/
  • helm repo search -l gitlab/gitlab

gitlab-runner の chart があることを確認します

Specific runner のデプロイ

プロジェクトの Settings -> CI/CD からトークンを取得します
それを使って helm を実行します

  • helm install --namespace gitlab gitlab-runner gitlab/gitlab-runner --set gitlabUrl=https://gitlab.example.com:32443/ --set privileged=true --set runnerRegistrationToken=xxxxxxxxxxxxxxx

指定するパラメータは

  • gitlabURL
  • privileged (dind を使う場合は必須)
  • runnerRegistrationToken

になります
無事 Pod が動作すると画面からも Runner が登録されているのが確認できます

Shared runner のデプロイ

Shared Runner 用のトークンは Admin Area から取得します
Overview -> Runners にあります

デプロイコマンドは先程と同じです
トークンを取得する場所が異なる点だけ注意しましょう
また helm デプロイ時のリリース名も先程とは別の名前にしましょう

  • helm install --namespace gitlab gitlab-shared-runner gitlab/gitlab-runner --set gitlabUrl=https://gitlab.example.com:32443/ --set privileged=true --set runnerRegistrationToken=xxxxxxxxxxxxxxx

デプロイが完了すると一覧にも表示されるようになります

rbac と runners.config を設定する場合は

Runner が Gitlab からリポジトリを clone する場合に URL がおかしいというエラーが出る場合があります
また serviceAccount が default だと権限がないと言われてエラーになります
その場合は rbac.create と runners.config を設定してあげましょう

helm upgrade --namespace gitlab gitlab-shared-runner gitlab/gitlab-runner --set gitlabUrl=https://gitlab.example.com:32443/ --set privileged=true --set runnerRegistrationToken=xxxxxxxxxxxxxxx --set rbac.create=true --set runners.config="  
[[runners]]  
  clone_url = \"https://gitlab.example.com:32443/\"  
  [runners.kubernetes]  
    image = \"ubuntu:16.04\"  
"

runners.config はヒアドキュメントなので複数行で記載する必要があります

最後に

Gitlab の helm chart をデプロイする際に一緒に Runner もデプロイできるのですが DNS の関係や ACL の関係で一緒にインストールするのが難しい場合は --set gitlab-runner.install=false にして後からインストールしましょう

おまけ: values の取得方法

  • helm inspect values gitlab/gitlab-runner

参考サイト

2021年4月7日水曜日

Gitlab helm chart で gitlab をバージョンアップする方法

Gitlab helm chart で gitlab をバージョンアップする方法

概要

Gitlab helm chart で gitlab のバージョンアップする方法を紹介します

環境

  • Gitlab 13.10.2

やり方

まずはリポジトリを update して最新の helm chart を入手します

  • helm repo update

そして最新の gitlab が取得できているか確認します

  • helm search repo -l gitlab/gitlab | head

あとは upgrade します
global.gitlabVersion を使ってバージョンを指定することでアップグレードできます

例えば --set global.gitlabVersion=13.10.2 を指定して helm upgrade を実行します

ポイント

  • helm install 時に指定した --set がある場合はそれらもすべて指定すること
  • ノードのリソースが足りないと 0/3 nodes are available: 3 Insufficient memory. となりアップデートに失敗する

前者は例えば global.hosts.domain などを指定して helm install した場合は upgrade 時も同じ用に指定しましょう

後者は新バージョンの Pod を先に作成してから古い Pod を削除する流れになるので新バージョンの Gitlab の Pod が動作するリソースが残っていないとエラーになるということです
つまり最低でも 2 つの Gitlab が動作するスペックの k8s クラスタを用意する必要があります

参考サイト

2021年4月6日火曜日

k8s で default の storageClass を作成する方法

k8s で default の storageClass を作成する方法

概要

作成した storageClass はデフォルトでは PersistentVolume で storageName を指定する必要があります
指定なしでも pv を作成する場合は default の storageClassName を作成する必要があります

環境

  • k8s 1.20.4

storageClass の作成

例えば nfs を使った storageClass を作成するには以下の用に作成します
https://hawksnowlog.blogspot.com/2021/03/how-to-use-nfs-as-storageclass-server-on-kubernetes.html

デフォルトにする

上記で作成した nfs の storageClass をデフォルトにするには以下を実行します

  • kubectl patch storageclass nfs -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

動作確認

  • kubectl get storageclasses.storage.k8s.io

default と表示されれば OK です
これで pv 作成時に storageClassName を指定しなくても自動で nfs から pv を作成してくれます

参考サイト

2021年3月18日木曜日

Gitlab 公式の helm chart でワイルドカード SSL 証明書を設定する方法

概要

Let’sEncrypt などで取得したワイルドカード SSL 証明書を使って Gitlab の helm chart に SSL 設定をする方法を紹介します
内部的には kubernetes の nginx-ingress が使われているのでそれの tls 機能を使います

環境

  • kubernetes 1.19.3
  • helm 3.5.2
  • Gitlab helm chart 4.9.3
  • kubernetes nginx-ingress-controller 0.41.2

手順

とりあえず先に手順を紹介します
そのあとでポイントなどを紹介します

証明書登録

Let’sEncrypt などで取得したワイルドカード証明書を secret に登録します

  • kubectl create secret tls gitlab-tls --cert=/path/to/tls.crt --key=/path/to/tls.key

デプロイ

helm chart をデプロイします
ワイルドカードを使って動作させる場合の最低限のオプションを指定しています
global.hosts.domain は自身で登録した DNS の FQDN を指定してください

helm install gitlab gitlab/gitlab \
  --timeout 600s \
  --set global.hosts.domain=your.domain.com \
  --set nginx-ingress.controller.service.type=NodePort \
  --set certmanager.install=false \
  --set global.ingress.configureCertmanager=false \
  --set global.ingress.tls.secretName=gitlab-tls

説明

Let’sEncrypt の SSL ワイルドカード証明書取得時に指定したコモンネームと同じコモンネームを global.hosts.domain に指定します
ワイルドカードドメインだからと言って例えばサブドメイン (global.hosts.domain=sub.your.domain.com) を指定したりするとエラーになります
nginx-ingress-controller の Pod のログを見るとわかりますが証明書に設定されているコモンネームと global.hosts.domain で指定されているコモンネームが異なっているというエラーが出ているとうまく設定できていないことになります
必ず取得時と同じコモンネームを指定しましょう


nginx-ingress.controller.service.type=NodePort は今回オンプレミス環境にデプロイするので指定しています
デフォルトだと type=Loadbalancer でデプロイされてしまいます
特に type=Loadbalancer でも問題ないのですが気持ち悪いので NodePort に変えておきます


certmanager.install=false と global.ingress.configureCertmanager=false と global.ingress.tls.secretName=gitlab-tls はワイルドカード SSL を使うのに必須の設定になります
secretName の部分は事前に secret に登録した際の名前を指定しましょう

動作確認

Pod がすべて動作しているか確認します
gitlab-webservice-default が動作していれば OK だと思います

  • kubectl get pod

あとは svc を調べてアクセスするポートを確認します

  • kubectl get svc

IP は nginx-ingress-controller Pod がデプロイされているノードの IP にアクセスします
調べ方は -o wide を使うと Pod が乗っているノードが確認できるのでそこからノードの一覧を使って IP を確認しましょう

  • kubectl get pod -o wide
  • kubectl get node -o wide

あとは IP を DNS にレコードに登録して gitlab.your.domain.com:port という感じでアクセスすれば Gitlab にアクセスできるはずです

補足

Gitlab 公式の helm chart の場合 nginx-ingress-controller の Pod は 2 つデプロイされます
デフォルトだとどのノードで動作するかは完全にランダムになるので再デプロイなどをすると nginx-ingress-controller の Pod の場所が変わりアクセスする IP も変わるので注意しましょう
特に DNS などを設定している場合はレコード情報を書き換えることになるのでそこも注意しましょう

解決策としては nginx-ingress-controller の Pod をノードの数と同じだけデプロイするように変更するか (もしくは Damonset を使うか) nodeSelector を使って nginx-ingress-controller の Pod を必ず特定のノードにデプロイするようにすれば IP を固定することができると思います

トラブルシューティング

再度やり直す場合は helm の delete と delete では削除されないリソースも削除してからやり直しましょう

  • helm delete gitlab
  • for i in `kubectl get all,cm,secret,ing,job,pvc -A -o name | grep gitlab`; do kubectl delete ${i}; done;

最後に

ワイルドカード証明書のコモンネームと global.hosts.domain の指定は必ず一致するようにしましょう

参考サイト

2021年3月16日火曜日

Python で kubernetes を操作する超入門

概要

kubernetes の API をコールするのに公式の Python クライアントがあります
今回は超入門ということで redis の Pods を k8s 上に構築してみました

環境

  • kubernetes v1.19.3
  • Python 3.8.3
  • pipenv 2020.8.13

インストール

  • pipenv install kubernetes

進め方

リファレンスを読みながら API をコールするための yaml 情報を Python で構築いく感じになります
フィールドがオブジェクトだったり dict だったりするのでそれをリファレンスで確認して何を使用するのか指定するのかを確認しながらコーディングしていくとやりやすいと思います

まずはバージョンを取得する

  • vim show_version.py
from kubernetes import client, config

config.load_kube_config()

v1 = client.VersionApi()
print(v1.get_code())
  • pipenv run python show_version.py

redis の PersistentVolumeClaim を作成する

storageClass は nfs を使って事前に作成しておきます
https://hawksnowlog.blogspot.com/2021/03/how-to-use-nfs-as-storageclass-server-on-kubernetes.html

  • vim apply_pvc.py
from kubernetes import client, config

config.load_kube_config()

api_instance = client.CoreV1Api()
body = client.V1PersistentVolumeClaim()
namespace = "default"
body.metadata = client.V1ObjectMeta(
  name="pvc1"
)
body.spec = client.V1PersistentVolumeClaimSpec(
  access_modes = [
    "ReadWriteOnce"
  ],
  resources = client.V1ResourceRequirements(
    requests = {
      "storage": "100Mi"
    }
  ),
  storage_class_name = "nfs",
)

api_response = api_instance.create_namespaced_persistent_volume_claim(namespace, body)
print(api_response)
  • pipenv run python apply_pvc.py
  • kubectl get pvc pvc1
NAME   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS       AGE
pvc1   Bound    pvc-b0386fce-8745-4e24-9cbe-e79b6602e671   100Mi      RWO            nfs                15s

redis の Deployment を作成する

長いですが Pod spec なども同じ用に作成するだけです

  • vim apply_deploy.py
from kubernetes import client, config

config.load_kube_config()

api_instance = client.AppsV1Api()
body = client.V1Deployment()
namespace = "default"
body.metadata = client.V1ObjectMeta(
  name="redis"
)
body.spec = client.ExtensionsV1beta1DeploymentSpec(
  replicas = 1,
  selector = client.V1LabelSelector(
    match_labels = {
      "name": "redis"
    }
  ),
  template = client.V1PodTemplateSpec(
    metadata = client.V1ObjectMeta(
      labels = {
        "name": "redis"
      }
    ),
    spec = client.V1PodSpec(
      containers = [
        client.V1Container(
          image = "redis:6",
          name = "redis",
          volume_mounts = [
            client.V1VolumeMount(
              mount_path = "/data",
              name = "pvc1"
            )
          ]
        )
      ],
      restart_policy = "Always",
      volumes = [
        client.V1Volume(
          name = "pvc1",
          persistent_volume_claim = client.V1PersistentVolumeClaimVolumeSource(
            claim_name = "pvc1"
          )
        )
      ]
    )
  )
)

api_response = api_instance.create_namespaced_deployment(namespace, body)
print(api_response)
  • pipenv run python apply_deploy.py
  • kubectl get pod redis-6965c4dcd7-7mptl
NAME                     READY   STATUS    RESTARTS   AGE
redis-6965c4dcd7-7mptl   1/1     Running   0          9m31s

redis の Service を作成する

NodePort を使ってアクセスします

  • vim apply_svc.py
from kubernetes import client, config

config.load_kube_config()

api_instance = client.CoreV1Api()
body = client.V1Service()
namespace = "default"
body.metadata = client.V1ObjectMeta(
  name="redis-svc"
)
body.spec = client.V1ServiceSpec(
  type = "NodePort",
  selector = {
    "name": "redis"
  },
  ports = [
    client.V1ServicePort(
      name = "6379",
      port = 6379,
      target_port = 6379,
      protocol = "TCP"
    )
  ]
)

api_response = api_instance.create_namespaced_service(namespace, body)
print(api_response)
  • pipenv run python apply_svc.py
  • kubectl get svc redis-svc
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
redis-svc   NodePort   10.105.106.45   <none>        6379:31806/TCP   5s

動作確認

  • redis-cli -h 192.168.100.10 -p 31806

おまけ: yaml からリソースを作成する

  • vim from_file.py
from kubernetes import client, config, utils

config.load_kube_config()
k8s_client = client.ApiClient()
ret = utils.create_from_yaml(k8s_client, "./pvc.yml")
print(ret)

最後に

慣れればリファレンス片手に簡単にコーディングできるようになると思います
動的に変わるようなマニフェストを作成したい場合やテンプレート化して管理したい場合に使えます