2021年3月4日木曜日

Gitlab 公式の helm chart を試してみた

概要

Gitlab 公式の helm chart を使って k8s 上に Gitlab を構築してみました
当然ですがそのままだと全く動かなかったのでポイントなどを紹介します
今回使用する k8s 環境は kubeadm で構築した独自の k8s 環境になります

環境

  • Ubuntu 18.04
  • k8s v1.20.4
  • helm 3.5.2
  • gitlab chart 4.9.1

事前準備

そもそも公式でいろいろ足りていなかったりバグがあるのでそれの準備をします

PersistentVolume の作成

公式の chart は PersistentVolumeClaim は作成してくれますが PersistentVolume は作成してくれません
おそらく環境によって StorageClass が違うので仕方ないのですがないので作成します
なお今回はローカルストレージをマウントして PersistenVolume を作成します
当然ノードが固定されてしまうので作成する Pod もそのノードに固定されてしまいます

  • vim pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv2
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  claimRef:
    namespace: gitlab
    name: gitlab-minio
  storageClassName: local-storage
  local:
    path: /mnt/pv2
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node1

---

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv3
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  claimRef:
    namespace: gitlab
    name: gitlab-prometheus-server
  storageClassName: local-storage
  local:
    path: /mnt/pv3
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node1

---

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv4
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  claimRef:
    namespace: gitlab
    name: redis-data-gitlab-redis-master-0
  storageClassName: local-storage
  local:
    path: /mnt/pv4
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node1

---

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv5
spec:
  capacity:
    storage: 50Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  claimRef:
    namespace: gitlab
    name: repo-data-gitlab-gitaly-0
  storageClassName: local-storage
  local:
    path: /mnt/pv5
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node1

ポイントは claimRef を使っている点です
こうすることで chart が自動で作成する pvc とこちらが手動で作成する pv を紐付けて使えるようにしてくれます
例えば name: repo-data-gitlab-gitaly-0 は chart をデプロイしてみるとわかりますがその名前で pvc がデプロイされます
必要なマウント先のディレクトリを作成して apply します

  • mkdir /mnt/pv1 /mnt/pv2 /mnt/pv3 /mnt/pv4 /mnt/pv5
  • kubectl apply -f pv.yml
  • kubectl get pv

PostgreSQL の作成

コンテナで動作させています
gitlab ユーザと gitlabhq_production データベースの作成をしましょう
過去に紹介した手順で作成すれば問題ありません
gitlab ユーザに設定するパスワードはあとで k8s の secret に登録するのでメモしておきましょう

secret の登録

postgres に接続する gitlab ユーザのパスワードを事前に登録しておきます
chart などを事前にデプロイしておりすでに作成してある場合は削除しましょう

  • kubectl delete secret gitlab-postgresql-password -n gitlab
kubectl create secret generic gitlab-postgresql-password \
    --namespace gitlab \
    --from-literal postgresql-password='xxxxx' \
    --from-literal postgresql-postgres-password='xxxxx'

xxxxx の部分は好きなパスワードを入力してください
namespace は後述しているのでない場合は作成しましょう

helm のインストール

今回は Ubuntu にインストールするので apt を使う手順でインストールしました

  • curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
  • apt-get install apt-transport-https --yes
  • echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
  • apt-get -y update
    apt-get -y install helm

gitlab chart の取得

準備ができたら chart をデプロイしていきます

  • helm repo add gitlab https://charts.gitlab.io/

namespace の作成

gitlab 用の namespace を作成します

  • kubectl create namespace gitlab

デプロイ

ではデプロイしていきます
オプションがいくつかあるのであとで説明します

helm install gitlab gitlab/gitlab \
  --namespace gitlab \
  --timeout 600s \
  --set global.hosts.domain=gitlab.example.com \
  --set global.hosts.externalIP=192.168.100.10 \
  --set certmanager-issuer.email=name@domain.com \
  --set postgresql.install=false \
  --set global.psql.host=192.168.100.11 \
  --set global.psql.password.secret=gitlab-postgresql-password \
  --set global.psql.password.key=postgresql-password

global.hosts.domain, global.hosts.externalIP, certmanager-issuer.email は内部的に使用している external_url と SSL 証明書取得に必要なパラメータになります
postgresql.install, global.psql.host, global.psql.password.secret, global.psql.password.key が外部に構築した PostgreSQL の情報を設定するオプションになります
postgresql.install=false にすることで chart での postgres の構築はしなくなります
global.psql.host は postgres が LISTEN している IP を指定します
ポートも指定できますが今回はポートは 5432 から変更していないので指定していません
global.psql.password.secretglobal.psql.password.key は k8s に登録した secret の情報になります
前者が secret 自体の名前で後者が from-literal で登録した key/value の key の部分を指定します

動作確認

まずは Pods がすべて正常に動作しているか確認しましょう

  • kubectl get pod -n gitlab
NAME                                                  READY   STATUS             RESTARTS   AGE
gitlab-cainjector-5c6477876c-wtndw                    1/1     Running            0          7m44s
gitlab-cert-manager-795fc9bc98-dkwcj                  1/1     Running            0          7m44s
gitlab-gitaly-0                                       1/1     Running            0          7m44s
gitlab-gitlab-exporter-7d48bc7647-fggj2               1/1     Running            0          7m44s
gitlab-gitlab-runner-57748568f7-78m6f                 0/1     CrashLoopBackOff   2          7m44s
gitlab-gitlab-shell-57b945dc6d-9jd57                  0/1     Pending            0          7m29s
gitlab-gitlab-shell-57b945dc6d-tc2ks                  1/1     Running            0          7m44s
gitlab-issuer-1-jbzc8                                 0/1     Completed          0          7m44s
gitlab-migrations-1-wvnzf                             0/1     Completed          0          7m44s
gitlab-minio-7754b8d9d9-tnvcm                         1/1     Running            0          7m44s
gitlab-minio-create-buckets-1-9t46l                   0/1     Completed          0          7m44s
gitlab-nginx-ingress-controller-87dcb7cc4-7dpkz       0/1     Pending            0          7m43s
gitlab-nginx-ingress-controller-87dcb7cc4-nm7r5       1/1     Running            0          7m44s
gitlab-nginx-ingress-default-backend-d66cb657-qfzpb   1/1     Running            0          7m43s
gitlab-prometheus-server-6878cb55d4-htmjr             2/2     Running            0          7m43s
gitlab-redis-master-0                                 2/2     Running            0          7m44s
gitlab-registry-7bd7d55766-bf8xw                      1/1     Running            0          7m43s
gitlab-registry-7bd7d55766-k69ql                      1/1     Running            0          7m43s
gitlab-sidekiq-all-in-1-v1-77b676769c-xtbbp           1/1     Running            0          7m44s
gitlab-task-runner-65b5dc5764-897hp                   1/1     Running            0          7m44s
gitlab-webservice-default-f7f7cbc5f-8474w             2/2     Running            0          7m44s
gitlab-webservice-default-f7f7cbc5f-v47np             2/2     Running            0          7m44s

gitlab-runner は dind 環境が必要で今回はセットアップしません
gitlab-webservice-default が Running になっていれば OK です
gitlab の chart では nginx-ingress-controller が動作しており Host 名ごとに gitlab や registry, minio をバランシングしています

  • kubectl get ingress -n gitlab
AME                        CLASS    HOSTS                                                ADDRESS   PORTS     AGE
gitlab-minio                <none>   minio.k8s.jp-east-1.devops.teamops.nifcloud.net                80, 443   12m
gitlab-registry             <none>   registry.k8s.jp-east-1.devops.teamops.nifcloud.net             80, 443   12m
gitlab-webservice-default   <none>   gitlab.k8s.jp-east-1.devops.teamops.nifcloud.net               80, 443   12m

Service で LISTEN しているポートがわかるので確認します
Type は Loadbalancer ですが実際は NodePort でアクセスします

  • kubectl get svc gitlab-nginx-ingress-controller -n gitlab
NAME                              TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                   AGE
gitlab-nginx-ingress-controller   LoadBalancer   10.108.0.100   <pending>     80:31657/TCP,443:32332/TCP,22:31328/TCP   15m

https://gitlab.example.com:32332/ にアクセスすると root のログイン画面が表示されます
証明書は certmanager という Pods が作成しているのですが自己証明書なのでブラウザで警告が表示されると思います
パスワードは k8s の secret に保存されているので secret から取得します

  • kubectl get secret gitlab-gitlab-initial-root-password -n gitlab -ojsonpath='{.data.password}' | base64 --decode ; echo

ここで表示されたパスワードで root ログインすると Gitlab にログインできます

トラブルシューティング

PV の作成がうまくできてない場合に発生しました
PV を作成してうまく redis や gitaly が上がってきて migration Pod がうまく成功すればいいのですが migration が失敗する場合に出ます

MountVolume.SetUp failed for volume "init-webservice-secrets" : failed to sync secret cache: timed out waiting for the condition
no persistent volumes available for this claim and no storage class is set

最後に

やはりというか嵌りポイントは多かったです
そもそも k8s についてかなりの知識がないとトラブルシューティングもできないので Omnibus Install の Gitlab や docker イメージの Gitlab に比べるとかなりハードルの高いデプロイ方法かなと思います

参考サイト

2021年3月3日水曜日

外部に移行した registry で Gitlab 認証を使う方法

概要

過去に Gitlab の registry 機能を外部に移行する方法を紹介しました
そのままでは registry に認証が何もないので誰でも login/push できてしまいます
今回は registry と Gitlab を連携して registry に Gitlab の認証を付けたいと思います
デプロイは前回紹介した docker-compose をベースに修正して行います

環境

  • Gitlab-ee 13.8.4
  • registry

registry 用の証明書と鍵の準備

認証情報のやり取りをする際に暗号化するための証明書と鍵を使います
基本的には registry で https を使うための証明書と鍵があれば OK です
LetsEncrypt などで取得したもので OK です

registry 用の config.yml の作成

registry に必要な最低限の設定も含めて config.yml を作成します

  • vim config.yml
version: 0.1
log:
  fields:
    service: registry
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
  delete:
    enabled: true
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
auth:
  token:
    realm: https://gitlab.example.com/jwt/auth
    service: container_registry
    issuer: gitlab-issuer
    rootcertbundle: /home/tls.crt

ポイントは 2 箇所で storage.delete.enabled = trueauth の部分です
前者は registry のタグ情報を Gitlab 側から削除するのに必須です
後者が認証に必須の設定になります
まず realm は Gitlab の URL + /jwt/auth を記載します
このエンドポイントに対して認証情報を取りに行きます
service と issuer は固定になります
container_registrygitlab-issuer を入力しましょう
rootcerbundle は先程説明した証明書になります
registry 側では証明書を配置することになるのでコンテナに証明書を配置してそのパスを指定します
証明書の配置はこのあと docker-compose.yml 側で行います

gitlab.rb の編集

次に gitlab 側の設定をします
基本にはすでに外部の連携が済んでいる場合は鍵の情報を埋め込むだけになります

gitlab_rails['registry_enabled'] = true
gitlab_rails['registry_host'] = "registry.gitlab.example.com"
gitlab_rails['registry_api_url'] = "http://registry:5000"
gitlab_rails['registry_issuer'] = "gitlab-issuer"
registry['internal_key'] = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBA\n-----END PRIVATE KEY-----"
gitlab_rails['registry_key_path'] = "/home/tls.key"

追加で必要そうなのは registry_issuerinternal_keyregistry_key_path になります
internal_key には冒頭で説明した鍵の方を直接記載します
改行は必ず \n に置換して入力してください
なお上記はサンプルで途中を省いているので実際は鍵の情報すべてを入力してください
そして registry_key_path はその鍵の情報を保存するパスをしていします
registry 側から公開鍵で暗号化されたデータをこの鍵を使って復号化して認証情報を取得し照合します

docker-compose 全体

長いですが全体を紹介します
証明書や config ファイルをマウントする部分が追加になっている感じです

  • vim docker-compose.yml
version: "3.8"

services:
  gitlab:
    image: gitlab/gitlab-ee:13.8.4-ee.0
    ports:
      - "22:22"
      - "80:80"
    volumes:
      - logs:/var/log/gitlab
      - etc_gitlab:/etc/gitlab
      - dot_ssh:/var/opt/gitlab/.ssh
      - uploads:/var/opt/gitlab/gitlab-rails/uploads
      - shared:/var/opt/gitlab/gitlab-rails/shared
      - builds:/var/opt/gitlab/gitlab-ci/builds
      - git-data:/var/opt/gitlab/git-data
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        roles ['application_role']

        external_url 'https://gitlab.example.com'
        nginx['enable'] = true
        nginx['listen_port'] = 80
        nginx['listen_https'] = false

        gitlab_rails['registry_enabled'] = true
        gitlab_rails['registry_host'] = "registry.gitlab.example.com"
        gitlab_rails['registry_api_url'] = "http://registry:5000"
        gitlab_rails['registry_issuer'] = "gitlab-issuer"
        registry['internal_key'] = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBA\n-----END PRIVATE KEY-----"
        gitlab_rails['registry_key_path'] = "/home/tls.key"

        postgresql['enable'] = false
        gitlab_rails['db_adapter'] = 'postgresql'
        gitlab_rails['db_encoding'] = 'unicode'
        gitlab_rails['db_host'] = 'postgres'
        gitlab_rails['db_password'] = 'xxxxxxxx'

        redis['enable'] = false
        gitlab_rails['redis_host'] = "redis"

        prometheus['enable'] = false

        gitlab_workhorse['prometheus_listen_addr'] = "0.0.0.0:9229"
        gitaly['prometheus_listen_addr'] = "0.0.0.0:9236"
        node_exporter['listen_address'] = '0.0.0.0:9100'
        gitlab_exporter['listen_address'] = '0.0.0.0'
        gitlab_exporter['listen_port'] = '9168'
        sidekiq['listen_address'] = '0.0.0.0'
        puma['listen'] = '0.0.0.0'
        puma['port'] = 8080
        gitlab_rails['monitoring_whitelist'] = ['127.0.0.0/8', '172.30.1.0/24']
        gitlab_rails['prometheus_address'] = 'prometheus:9090'
        nginx['status']['options'] = {
          "server_tokens" => "off",
          "access_log" => "off",
          "allow" => "172.30.1.0/24",
          "deny" => "all",
        }
    depends_on:
      - redis
    deploy:
      mode: replicated
      replicas: 2
      placement:
        max_replicas_per_node: 1
  gitlab-runner:
    image: gitlab/gitlab-runner:v13.6.0
  registry:
    image: registry:2
    volumes:
      - registry:/var/lib/registry
      - /root/docker_gitlab/registry/config.yml:/etc/docker/registry/config.yml
      - /root/docker_gitlab/registry/tls.crt:/home/tls.crt
    deploy:
      placement:
        constraints:
          - node.hostname == node1
  registry_web:
    image: nginx:1.19.7
    ports:
      - "81:80"
    volumes:
      - /root/docker_gitlab/registry_nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - registry
    deploy:
      placement:
        constraints:
          - node.hostname == node1
  postgres:
    image: postgres:11.10
    volumes:
      - postgres:/var/lib/postgresql/data/pgdata
      - /root/docker_gitlab/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
    environment:
      POSTGRES_PASSWORD: xxxxxxxx
      PGDATA: /var/lib/postgresql/data/pgdata
    deploy:
      placement:
        constraints:
          - node.hostname == node1
  redis:
    image: redis:6
    volumes:
      - redis:/data
    depends_on:
      - postgres
    command: ["redis-server", "--appendonly", "yes"]
    deploy:
      placement:
        constraints:
          - node.hostname == node1
  prometheus:
    image: prom/prometheus:v2.25.0
    ports:
      - "9090:9090"
    volumes:
      - /root/docker_gitlab/prometheus:/prometheus-data
    command: ["--config.file=/prometheus-data/prometheus.yml"]
    deploy:
      placement:
        constraints:
          - node.hostname == node1
  alertmanager:
    image: prom/alertmanager:v0.21.0
    volumes:
      - /root/docker_gitlab/alertmanager:/alertmanager
    ports:
      - "9093:9093"
    command: ["--config.file=/alertmanager/alertmanager.yml"]
    user: "0:0"
    deploy:
      placement:
        constraints:
          - node.hostname == node1
  grafana:
    image: grafana/grafana:7.4.2
    ports:
      - "3000:3000"
    volumes:
      - grafana:/var/lib/grafana
      - /root/docker_gitlab/grafana/grafana.ini:/etc/grafana/grafana.ini
    deploy:
      placement:
        constraints:
          - node.hostname == node1

volumes:
  logs:
    driver: local
  etc_gitlab:
    driver_opts:
      type: nfs
      o: "addr=192.168.200.10,rw,nfsvers=4"
      device: ":/etc_gitlab"
  dot_ssh:
    driver_opts:
      type: nfs
      o: "addr=192.168.200.10,rw,nfsvers=4"
      device: ":/dot_ssh"
  uploads:
    driver_opts:
      type: nfs
      o: "addr=192.168.200.10,rw,nfsvers=4"
      device: ":/uploads"
  shared:
    driver_opts:
      type: nfs
      o: "addr=192.168.200.10,rw,nfsvers=4"
      device: ":/shared"
  builds:
    driver_opts:
      type: nfs
      o: "addr=192.168.200.10,rw,nfsvers=4"
      device: ":/builds"
  git-data:
    driver_opts:
      type: nfs
      o: "addr=192.168.200.10,rw,nfsvers=4"
      device: ":/git-data"
  registry:
    driver: local
  postgres:
    driver: local
  redis:
    driver: local
  grafana:
    driver: local

networks:
  default:
    attachable: true
    ipam:
     driver: default
     config:
       - subnet: 172.30.1.0/24

動作確認

  • docker stack deploy -c docker-compose.yml

でデプロイして動作確認します
registry に login して Gitlab に存在するユーザでなければログインできないことを確認しましょう

参考サイト

2021年3月2日火曜日

Gitlab の Snippets 機能を使ったみた

概要

Gitlab の Snippets 機能はあるファイルの内容を Gitlab でホスティングして HTML に組み込んだりダウンロードしたりできる機能です
今回はスニペットを新規に作成して HTML に組み込んでみました

環境

  • Gitlab-ee 13.8.4

スニペットの作成

まずはスニペットを作成しましょう
左メニューの「Snippets」から新規作成します
今回は Ruby のサンプルコードを作成しました
Title や Description は自由に設定しましょう
ファイル名の拡張子に .rb を指定するとスニペットの内容を Ruby コードとして認識してくれてハイライトなどしてくれます

そして下にある公開情報を設定します
今回はスニペットの HTML 組み込みを試すので Public を指定します

プロジェクトの公開設定

スニペットを Public だけにしただけでは組み込みスニペットは使えません
プロジェクト自体の公開設定も Public にしましょう
左メニューの「Setting」->「General」->「Visibility, project features, permissions」から設定します

組み込み用 HTML の取得

あとは組み込むための HTML を取得します
作成したスニペットを見ると「Embed」ボタンがあるのでそこから取得します

動作確認用の HTML ファイルの作成

何でも OK です
先程取得した組み込み用 HTML を記載しましょう

<html>
<head>
</head>
<body>
  <script src="https://gitlab.example.com/root/bb/-/snippets/2.js"></script>
</body>
</html>

あとは nginx などで適当に確認すると以下のように Gitlab に作成した Snippets の内容が確認できると思います

スニペットのダウンロード

スニペットのページに raw の URL とダウンロード用の URL が取得できるのでコピーして使いましょう

ダウンロードの URL は試した見た感じ txt ファイルとして保存されました
もしかするとブラウザの挙動にもよるかなと思います

最後に

イメージ的には Github の Pages の機能に近いと思います
Gitlab にも拡張機能として Pages がありますが Snippets はデフォルトで使える機能になります

参考サイト

2021年3月1日月曜日

Ubuntu18.04 で DNS サーバを設定する方法

概要

/etc/resolv.conf を直接編集することはできないので systemd-resolved を使って書き換えます

環境

  • Ubuntu 18.04.4

/etc/systemd/resolved.conf 書き換え

  • vim /etc/systemd/resolved.conf
[Resolve]
DNS=8.8.8.8 8.8.4.4

systemd-resolved 再起動

  • systemctl restart systemd-resolved

/etc/resolv.conf のシンボリックリンク変更

  • ln -f -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

デフォルトだと /run/systemd/resolve/stub-resolv.conf を使っておりローカルを経由する設定になっている

動作確認

  • dig google.com

ローカルを経由せずに指定した DNS リゾルバに直接聞きに行ってることが確認できるはず

参考サイト

2021年2月28日日曜日

kubernetes に Ingress をデプロイして外部からアクセスできるようにしてみる

概要

k8s で Service に対して外部からアクセスできるようにする場合は基本的には Ingress が必要になります
過去に minikube を使った Ingress の設定方法は紹介しました
今回は kubeadm で構築した環境に Ingress をデプロイしてみたいと思います

環境

  • Ubuntu18.04
  • kubernetes v1.20.4

Nginx Ingress Controller のデプロイ

今回は Nginx Ingress Controller を使います

Nginx Ingress Controller の取得

  • git clone https://github.com/nginxinc/kubernetes-ingress/
  • cd kubernetes-ingress/deployments
  • git checkout v1.10.0

RBAC のデプロイ

  • kubectl apply -f common/ns-and-sa.yaml
  • kubectl apply -f rbac/rbac.yaml
  • kubectl apply -f rbac/ap-rbac.yaml
namespace/nginx-ingress created
serviceaccount/nginx-ingress created

clusterrole.rbac.authorization.k8s.io/nginx-ingress created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress created

clusterrole.rbac.authorization.k8s.io/nginx-ingress-app-protect created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-app-protect created

nginx の共通設定のデプロイ

  • kubectl apply -f common/default-server-secret.yaml
  • kubectl apply -f common/nginx-config.yaml
  • kubectl apply -f common/ingress-class.yaml
secret/default-server-secret created

configmap/nginx-config created

ingressclass.networking.k8s.io/nginx created

カスタムリソースのデプロイ

  • kubectl apply -f common/crds/k8s.nginx.org_virtualservers.yaml
  • kubectl apply -f common/crds/k8s.nginx.org_virtualserverroutes.yaml
  • kubectl apply -f common/crds/k8s.nginx.org_transportservers.yaml
  • kubectl apply -f common/crds/k8s.nginx.org_policies.yaml
  • kubectl apply -f common/crds/k8s.nginx.org_globalconfigurations.yaml
  • kubectl apply -f common/global-configuration.yaml
customresourcedefinition.apiextensions.k8s.io/virtualservers.k8s.nginx.org created

customresourcedefinition.apiextensions.k8s.io/virtualserverroutes.k8s.nginx.org created

customresourcedefinition.apiextensions.k8s.io/transportservers.k8s.nginx.org created

customresourcedefinition.apiextensions.k8s.io/policies.k8s.nginx.org created

customresourcedefinition.apiextensions.k8s.io/globalconfigurations.k8s.nginx.org created

globalconfiguration.k8s.nginx.org/nginx-configuration created

Ingress Controller のデプロイ

  • kubectl apply -f deployment/nginx-ingress.yaml
  • kubectl apply -f daemon-set/nginx-ingress.yaml
deployment.apps/nginx-ingress created

daemonset.apps/nginx-ingress created

service のデプロイ

  • kubectl create -f service/nodeport.yaml
service/nginx-ingress created

これでホストのどこかのポートで待ち受けることできます
今回は 31451 と 30023 で LISTEN しています

  • kubectl get svc -n nginx-ingress
NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
nginx-ingress   NodePort   10.107.240.71   <none>        80:31451/TCP,443:30023/TCP   4m38s

Ingress Controller が動作しているか確認

  • kubectl get pods --namespace=nginx-ingress
AME                            READY   STATUS    RESTARTS   AGE
nginx-ingress-f69f79478-5gl72   1/1     Running   0          55m
nginx-ingress-k29kh             1/1     Running   0          42m

今回は daemonSets もデプロイしているので 2 つあります

使ってみる

Pod と Service をデプロイします
そして Service に対して Ingress 経由でアクセスできるようにしてみます

  • vim apple.yml
kind: Pod
apiVersion: v1
metadata:
  name: apple-app
  labels:
    app: apple
spec:
  containers:
    - name: apple-app
      image: hashicorp/http-echo
      args:
        - "-text=apple"
---

kind: Service
apiVersion: v1
metadata:
  name: apple-service
spec:
  selector:
    app: apple
  ports:
    - port: 5678
  • vim ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: test.app.com
    http:
      paths:
        - path: /apple
          backend:
            serviceName: apple-service
            servicePort: 5678
  • kubectl apply -f apple.yml
  • kubectl create -f ingress.yml

最小構成の場合ワーカー側のノードの IP で LISTEN しています
なのでノードの IP にアクセスすればどの IP でもアクセスできます
アクセスする際は host ベースの振り分けをしていので Host を指定するようにしましょう

  • curl -H "Host: test.app.com" node1:31451/apple

もちろんノードの IP に DNS を設定して FQDN でアクセスすれば Host ヘッダなしでアクセスできるようになります

トラブルシューティング: うまく pods が起動しない

自分が遭遇したエラーは error retrieving k8s version: Get "https://10.96.0.1:443/version?timeout=32s": dial tcp 10.96.0.1:443: i/o timeout というエラーで nginx-ingress-controller の pods から ClusterIP を経由して k8s の API をコールするところでエラーになりました
原因は k8s を構築する際の flannel の設定で --pod-network-cidr=10.244.0.0/16 を忘れていたのと指定したネットワークがホストのネットワークと被っていたせいでうまく通信できなかったのが原因でした

最後に

Nginx Ingress Controller をデプロイして外部から k8s 環境にデプロイしたアプリにアクセスできるようにしてみました
結構複雑なので使いこなすとなるとかなり大変かなと思います
今回のように master/node の 2 台最小構成なのであれば NodePort を使って外部からアクセスするようになります

参考サイト

2021年2月27日土曜日

kubeadm で構築した k8s で coredns がうまく起動しない場合の対処方法

概要

k8s 構築時に coredns がうまく起動しないケースがありました
対処方法を紹介します

環境

  • Ubuntu18.04
  • kubernetes v1.20.4

ホストの DNS の設定を見直す

Ubuntu18.04 であれば /etc/resolv.conf に記載されているリゾルバ名がローカルなどになっているとうまく動作しないことがあるようです
8.8.8.8 などに変更してみましょう
変更方法はこちらで紹介しています

/etc/hosts にノードの情報を記載する

ホスト名を master や node1 にしている場合はそれらのホスト名で自信を名前解決できる必要があります
/etc/hosts などに記載して対応しましょう

  • vim /etc/hosts
127.0.0.1       localhost master

cgroupdriver に systemd を設定する

これはあまり関係ないかもしれないのですが docker を使っている場合に kubeadm で構築時に警告が出ます
systemd を使うように修正するには以下のように修正します

  • vim /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"]
}
  • systemctl daemon-reload
  • systemctl restart docker

動作確認

これで再度 kubeadm init/join してみましょう
うまく coredns が起動できていれば OK です

  • kubectl get all --all-namespaces
NAMESPACE     NAME                                 READY   STATUS    RESTARTS   AGE
kube-system   pod/coredns-74ff55c5b-ltv9j          1/1     Running   0          23m
kube-system   pod/coredns-74ff55c5b-nl5st          1/1     Running   0          23m
kube-system   pod/etcd-master                      1/1     Running   0          23m
kube-system   pod/kube-apiserver-master            1/1     Running   0          23m
kube-system   pod/kube-controller-manager-master   1/1     Running   0          23m
kube-system   pod/kube-flannel-ds-bn4s2            1/1     Running   0          22m
kube-system   pod/kube-flannel-ds-z7nvs            1/1     Running   0          22m
kube-system   pod/kube-proxy-h6sfj                 1/1     Running   0          23m
kube-system   pod/kube-proxy-tj8p6                 1/1     Running   0          23m
kube-system   pod/kube-scheduler-master            1/1     Running   0          23m
NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  23m
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   23m
NAMESPACE     NAME                             DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/kube-flannel-ds   2         2         2       2            2           <none>                   22m
kube-system   daemonset.apps/kube-proxy        2         2         2       2            2           kubernetes.io/os=linux   23m
NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   2/2     2            2           23m
NAMESPACE     NAME                                DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-74ff55c5b   2         2         2       23m

2021年2月26日金曜日

Omnibus Gitlab のオブジェクトストレージの機能を使ってみた

概要

Omnibus Gitlab にはアップロードした画像や CI でビルドした成果物などをオブジェクトストレージにアップロードする機能があります
デフォルトではローカルストレージに保存するため容量が逼迫するおそれがありますがオブジェクトストレージ機能を使うことで回避することができます
今回はオブジェクトストレージ機能の使い方の紹介をしたいと思います
なお今回はニフクラのオブジェクトストレージを使っています
S3 や Google Cloud Storage でも代用可能です

環境

  • Gitlab-ee 13.9.1

バケットの作成

8 つ作成します
公式のドキュメントを見る限り現時点では 8 つの成果物でオブジェクトストレージ機能が使えるようです

バケットの名前はシステムで一意なのですでに使わている場合は別の名前をつけましょう

gitlab.rb の編集

オブジェクトストレージを使う設定を記載します
認証情報と先程作成したバケット情報を記載します

  • vim /etc/gitlab/gitlab.rb
external_url 'https://gitlab.example.com'

gitlab_rails['object_store']['enabled'] = true
gitlab_rails['object_store']['proxy_download'] = true
gitlab_rails['object_store']['connection'] = {
  "provider" => "AWS",
  "region" => "jp-west-1",
  "aws_access_key_id" => "xxxxxxxxxx",
  "aws_secret_access_key" => "xxxxxxxxxxxx",
  "endpoint" => "https://jp-west-1.storage.api.nifcloud.com",
  "aws_signature_version" => 2
}
gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts'
gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-external-diffs'
gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs-objects'
gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads'
gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages'
gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy'
gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state'
gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'

設定反映

  • gitlab-ctl reconfigure

動作確認

一番簡単な uploads のバケットを使ってみます
適当に issue を作成しコメントにファイルをアップロードしてみましょう

これでオブジェクトストレージ側を見てみるとファイルがアップロードされているのが確認できると思います

注意点

ファイルをアップロードしたコメントを削除してもオブジェクトストレージ側にあるファイルは削除されませんでした
おそらく別の箇所などからもリンクされている可能性があるので削除していないのかと思いますがオブジェクトストレージ側にはファイルが溜まり続ける可能性があるので従量課金の場合は注意しましょう

最後に

今回は uploads だけ試しましたが dependency_proxyterraform_state などもあるので興味があればどの機能に対応しているか調べてみると良いかなと思います

参考サイト