Gitpod Self-HostedをオンプレKubernetesにインストールする

GitpodとはWeb IDEのことです。
注目したのはGitLabと連携できて開発環境を自動構築できるところです。
これをオンプレミスで構築すれば、セキュリティ要件でクラウドにデータを保存できない
プロジェクトでも、443ポートだけ通せばテレワークで作業できるのでは?
安価なchromebookだけ渡しておけばどこでも仕事できるのでは?
と思いましたのでSelf-Hosted版を構築してみました。

結構大変でしたので誰かの参考になれば幸いです。

構築環境

今回はテスト目的なので、以下の図のように
必要なサーバーを全て1台のESXi上で起動しています。

gitpod_architecture.png

【GitLab】
前回構築したGitLab を利用しています。
正規の証明書でHTTPSアクセスできるようにしてください。

【Kubernetes】
Ubuntuにkubeadmでシングルノードクラスター構成でインストールしました。
コンテナランタイムはDockerです。

ubuntu@gitpod:~$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
ubuntu@gitpod:~$ kubectl get nodes
NAME     STATUS   ROLES                  AGE   VERSION
gitpod   Ready    control-plane,master   10m   v1.20.7

ネットワークにはFlannel、LoadBalancerにはMetalLBを利用しています。
その辺りの設定はこちら と一緒です。

ubuntu@gitpod:~$ kubectl get all --all-namespaces
NAMESPACE        NAME                                 READY   STATUS    RESTARTS   AGE
kube-system      pod/coredns-74ff55c5b-2p6gg          1/1     Running   0          10m
kube-system      pod/coredns-74ff55c5b-nqxlk          1/1     Running   0          10m
kube-system      pod/etcd-gitpod                      1/1     Running   0          10m
kube-system      pod/kube-apiserver-gitpod            1/1     Running   0          10m
kube-system      pod/kube-controller-manager-gitpod   1/1     Running   0          3m19s
kube-system      pod/kube-flannel-ds-hgfjf            1/1     Running   0          10m
kube-system      pod/kube-proxy-lqqp6                 1/1     Running   0          10m
kube-system      pod/kube-scheduler-gitpod            1/1     Running   0          10m
metallb-system   pod/controller-675995489c-m6mmd      1/1     Running   0          7m45s
metallb-system   pod/speaker-5zm87                    1/1     Running   0          7m45s

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  11m
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   10m

NAMESPACE        NAME                             DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system      daemonset.apps/kube-flannel-ds   1         1         1       1            1           <none>                   10m
kube-system      daemonset.apps/kube-proxy        1         1         1       1            1           kubernetes.io/os=linux   10m
metallb-system   daemonset.apps/speaker           1         1         1       1            1           kubernetes.io/os=linux   7m45s

NAMESPACE        NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
kube-system      deployment.apps/coredns      2/2     2            2           10m
metallb-system   deployment.apps/controller   1/1     1            1           7m45s

NAMESPACE        NAME                                    DESIRED   CURRENT   READY   AGE
kube-system      replicaset.apps/coredns-74ff55c5b       2         2         2       10m
metallb-system   replicaset.apps/controller-675995489c   1         1         1       7m45s

加えて、Dynamic ProvisioningができるVolumeが必要です。
今回はテストなのでhostPathを利用しています。
設定方法など詳しくは こちら をご確認ください。

ubuntu@gitpod:~$ kubectl get sc
NAME                 PROVISIONER               RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
standard (default)   kubernetes.io/host-path   Delete          Immediate           false                  100s

Helm を使うのでインストールしてください。

ubuntu@gitpod:~$ helm version
version.BuildInfo{Version:"v3.6.0", GitCommit:"7f2df6467771a75f5646b7f12afb408590ed1755", GitTreeState:"clean", GoVersion:"go1.16.3"}

GitpodにはHTTPS証明書が必要です。
Let’s Encrypt証明書を発行するためにCertbotをインストールしてください。
インストール方法はこちら をご確認ください。

ubuntu@gitpod:~$ certbot --version
certbot 1.16.0

UbuntuのスペックはCPU4コアメモリ8GBで構築しています。
CPU2コアだとスペック不足で起動できませんでした。
あとUbuntuにインストールした場合32GBディスクを使用しました。

ubuntu@gitpod:~$ df -h
Filesystem                         Size  Used Avail Use% Mounted on
udev                               3.9G     0  3.9G   0% /dev
tmpfs                              797M  5.3M  791M   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv   78G   32G   43G  44% /
tmpfs                              3.9G     0  3.9G   0% /dev/shm
tmpfs                              5.0M     0  5.0M   0% /run/lock
tmpfs                              3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/sda2                          976M  107M  803M  12% /boot
/dev/loop0                         100M  100M     0 100% /snap/core/11167
/dev/loop1                          43M   43M     0 100% /snap/certbot/1201
/dev/loop3                          56M   56M     0 100% /snap/core18/2066
/dev/loop7                          32M   32M     0 100% /snap/snapd/10707
/dev/loop8                          33M   33M     0 100% /snap/snapd/12057
/dev/loop5                          62M   62M     0 100% /snap/core20/1026
/dev/loop2                          56M   56M     0 100% /snap/core18/1944
/dev/loop4                          70M   70M     0 100% /snap/lxd/19188
/dev/loop6                          68M   68M     0 100% /snap/lxd/20326
tmpfs                              797M     0  797M   0% /run/user/1000

【Dnsmasq】
gitpodは以下のようなワイルドカードドメインの名前解決ができないといけません。

your-domain.com *.your-domain.com *.ws.your-domain.com

hostsファイルじゃワイルドカードが解決できないので、
別途 dnsmasqを使ったDNSサーバ を構築しました。

インストール

準備ができましたら 公式の手順 に従いインストールを進めます。

values.custom.yamlを作成します。
ランダムな文字列に置き換えてください。

ubuntu@gitpod:~$ cat values.custom.yaml 
minio:
  accessKey: Fc73FWttRdCV
  secretKey: KPhH7R4XnmVv

ドキュメントのバージョンは0.9.0ですが、Helmはまだ0.8.0だったのでそちらで進めます。

ubuntu@gitpod:~$ helm repo add gitpod.io https://charts.gitpod.io
"gitpod.io" has been added to your repositories
ubuntu@k8s:~$ helm search repo gitpod
NAME                       	CHART VERSION	APP VERSION	DESCRIPTION                                       
gitpod.io/gitpod           	0.8.0        	0.1.5      	The core chart for Gitpod                         
gitpod.io/gitpod-selfhosted	0.4.0        	0.1.5      	The configuration chart for your Gitpod install...
ubuntu@gitpod:~$ helm install -f values.custom.yaml gitpod gitpod.io/gitpod --version=0.8.0

しばらく待つと以下のエラーになると思います。

Error: failed post-install: timed out waiting for the condition

podを確認すると色々起動できていませんね。
一つずつ解決していきます。

ubuntu@gitpod:~$ kubectl get po
NAME                                 READY   STATUS              RESTARTS   AGE
blobserve-7cbc7c58f-wh4kx            1/1     Running             0          7m8s
content-service-77bc5dc767-n4ftw     1/1     Running             0          7m7s
dashboard-6b599d77f5-2b4fn           1/1     Running             0          7m8s
image-builder-55bb474c5f-6slx9       2/2     Running             0          7m8s
messagebus-75b7dddf5b-kkpfq          1/1     Running             0          7m8s
minio-7b4d8ddbd8-b42pt               0/1     CrashLoopBackOff    4          7m7s
mysql-7cbb9c9586-scv9g               0/1     PodInitializing     0          7m8s
proxy-88f4c9674-8qvjz                0/1     ContainerCreating   0          7m8s
registry-6d64cf7dc9-fhtsl            1/1     Running             0          7m8s
registry-facade-nzx2b                0/1     ContainerCreating   0          7m8s
server-696b5547b5-b5k74              0/1     Init:1/2            0          7m7s
ws-daemon-g9gsn                      0/1     Init:0/2            0          7m8s
ws-manager-78f47f75d7-s7tf6          1/1     Running             0          7m7s
ws-manager-bridge-58f9774b79-f8thz   0/1     Init:0/2            0          7m7s
ws-proxy-866d5b7f9d-8hrld            0/1     ContainerCreating   0          7m7s
ws-scheduler-8967565c6-274vq         1/1     Running             0          7m7s

まずminioを修正します。
ログを確認すると以下のエラーになっていると思います。

ubuntu@gitpod:~$ kubectl logs minio-7b4d8ddbd8-b42pt

 You are running an older version of MinIO released 6 months ago 
 Update: Run `mc admin update` 


ERROR Unable to initialize backend: Unable to write to the backend
      > Please ensure MinIO binary has write permissions for the backend
      HINT:
        Use 'sudo chown -R <your-username> /export && sudo chmod u+rxw /export' to provide sufficient permissions.

これはhostPathを利用していることが原因なんですかね?
ヒントの通りhostPathのマウント先の権限を変更します。

ubuntu@gitpod:~$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM           STORAGECLASS   REASON   AGE
pvc-6ef4faa3-2202-4ef7-a889-10746bf3eec4   8Gi        RWO            Delete           Bound    default/mysql   standard                9m26s
pvc-9b63eba8-a154-4164-96a0-2b1c706facfb   500Gi      RWO            Delete           Bound    default/minio   standard                9m26s
ubuntu@gitpod:~$ kubectl describe pv pvc-9b63eba8-a154-4164-96a0-2b1c706facfb
Name:            pvc-9b63eba8-a154-4164-96a0-2b1c706facfb
Labels:          <none>
Annotations:     kubernetes.io/createdby: hostpath-dynamic-provisioner
                 pv.kubernetes.io/bound-by-controller: yes
                 pv.kubernetes.io/provisioned-by: kubernetes.io/host-path
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    standard
Status:          Bound
Claim:           default/minio
Reclaim Policy:  Delete
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        500Gi
Node Affinity:   <none>
Message:         
Source:
    Type:          HostPath (bare host directory volume)
    Path:          /tmp/hostpath_pv/6ee2885c-fe1c-449b-b58f-c102f2096101
    HostPathType:  
Events:            <none>

ubuntu@gitpod:~$ sudo chown -R ubuntu.ubuntu /tmp/hostpath_pv/6ee2885c-fe1c-449b-b58f-c102f2096101
ubuntu@gitpod:~$ kubectl delete po minio-7b4d8ddbd8-b42pt

minioが無事起動しました。

ubuntu@gitpod:~$ kubectl get po
NAME                                 READY   STATUS              RESTARTS   AGE
blobserve-7cbc7c58f-wh4kx            1/1     Running             0          15m
content-service-77bc5dc767-n4ftw     1/1     Running             0          15m
dashboard-6b599d77f5-2b4fn           1/1     Running             0          15m
image-builder-55bb474c5f-6slx9       2/2     Running             0          15m
messagebus-75b7dddf5b-kkpfq          1/1     Running             0          15m
minio-7b4d8ddbd8-lbvpj               1/1     Running             0          34s
mysql-7cbb9c9586-scv9g               1/1     Running             0          15m
proxy-88f4c9674-8qvjz                0/1     ContainerCreating   0          15m
registry-6d64cf7dc9-fhtsl            1/1     Running             0          15m
registry-facade-nzx2b                0/1     ContainerCreating   0          15m
server-696b5547b5-b5k74              1/1     Running             0          15m
ws-daemon-g9gsn                      0/1     Init:0/2            0          15m
ws-manager-78f47f75d7-s7tf6          1/1     Running             0          15m
ws-manager-bridge-58f9774b79-f8thz   1/1     Running             0          15m
ws-proxy-866d5b7f9d-8hrld            0/1     ContainerCreating   0          15m
ws-scheduler-8967565c6-274vq         1/1     Running             0          15m

次はws-daemonを修正します。
こちらはトラブルシューティング に解決方法が書いてあります。
僕の環境では以下のパスでした。

ubuntu@gitpod:~$ cat values.custom.yaml 
minio:
  accessKey: Fc73FWttRdCV
  secretKey: KPhH7R4XnmVv
components:
  wsDaemon:
    containerRuntime:
      nodeRoots:
      - /run/containerd/io.containerd.runtime.v2.task/moby/ 
ubuntu@gitpod:~$ helm upgrade --install -f values.custom.yaml gitpod gitpod.io/gitpod --version=0.8.0

今度はタイムアウトしないと思います。

Release "gitpod" has been upgraded. Happy Helming!
NAME: gitpod
LAST DEPLOYED: Tue Jun  8 09:56:03 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

ここまで来ればあとはproxyなど証明書関連が残ると思います。

ubuntu@gitpod:~$ kubectl get po
NAME                                 READY   STATUS              RESTARTS   AGE
blobserve-7cbc7c58f-wh4kx            1/1     Running             0          20m
content-service-77bc5dc767-n4ftw     1/1     Running             0          20m
dashboard-6b599d77f5-2b4fn           1/1     Running             0          20m
image-builder-8f58897b9-nd4sq        2/2     Running             0          44s
messagebus-75b7dddf5b-kkpfq          1/1     Running             0          20m
minio-7b4d8ddbd8-lbvpj               1/1     Running             0          5m27s
mysql-7cbb9c9586-scv9g               1/1     Running             0          20m
proxy-744df87ccf-hbcbk               0/1     ContainerCreating   0          44s
proxy-88f4c9674-8qvjz                0/1     ContainerCreating   0          20m
registry-6d64cf7dc9-fhtsl            1/1     Running             0          20m
registry-facade-nzx2b                0/1     ContainerCreating   0          20m
server-696b5547b5-b5k74              1/1     Running             0          20m
ws-daemon-4vknh                      1/1     Running             0          40s
ws-manager-7dcd698c76-m7rff          1/1     Running             0          44s
ws-manager-bridge-58f9774b79-f8thz   1/1     Running             0          20m
ws-proxy-866d5b7f9d-8hrld            0/1     ContainerCreating   0          20m
ws-scheduler-8967565c6-274vq         1/1     Running  

ドメインとhttpsを構成する

こちら の手順に進みます。

MetalLBの設定で以下のIPになっています。

ubuntu@gitpod:~$ kubectl describe svc proxy | grep -i ingress
LoadBalancer Ingress:     192.168.10.240

values.custom.yamlをさらに変更します。
今回hostnameはgitpod.tsuchinokometal.comとしています。
ご自身のドメインに書き換えてください。

ubuntu@gitpod:~$ cat values.custom.yaml 
minio:
  accessKey: Fc73FWttRdCV
  secretKey: KPhH7R4XnmVv
hostname: gitpod.tsuchinokometal.com
components:
  wsDaemon:
    containerRuntime:
      nodeRoots:
      - /run/containerd/io.containerd.runtime.v2.task/moby/ 
  proxy:
    loadBalancerIP: 192.168.10.240

Let’s Encrypt証明書を発行します。
こちら が参考になると思いますが、 手順は公式そのままですね。
rootで実行しました。

root@gitpod:~# export DOMAIN=gitpod.tsuchinokometal.com
root@gitpod:~# export EMAIL=[あなたのメールアドレス]
root@gitpod:~# export WORKDIR=$PWD/letsencrypt
root@gitpod:~# certbot certonly --config-dir $WORKDIR/config --work-dir $WORKDIR/work --logs-dir $WORKDIR/logs --manual --preferred-challenges=dns --email $EMAIL --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d *.ws.$DOMAIN -d *.$DOMAIN -d $DOMAIN

発行された証明書などをコピーします。

root@gitpod:~# mkdir -p /home/ubuntu/secrets/https-certificates
root@gitpod:~# find $WORKDIR/config/live -name "*.pem" -exec cp {} /home/ubuntu/secrets/https-certificates \;
root@gitpod:~# chown -R ubuntu.ubuntu /home/ubuntu/secrets/

シークレットを作成し、反映します。

ubuntu@gitpod:~$ openssl dhparam -out secrets/https-certificates/dhparams.pem 2048
ubuntu@gitpod:~$ kubectl create secret generic https-certificates --from-file=secrets/https-certificates
secret/https-certificates created
ubuntu@gitpod:~$ helm upgrade --install -f values.custom.yaml gitpod gitpod.io/gitpod --version=0.8.0

ようやく全てのpodがRUNNINGになりました。

ubuntu@gitpod:~$ kubectl get po
NAME                                 READY   STATUS    RESTARTS   AGE
blobserve-59c5d8994-7tcbd            1/1     Running   0          84s
content-service-b6dd66dcb-h8hmc      1/1     Running   0          84s
dashboard-789cf75d88-c77nd           1/1     Running   0          84s
image-builder-8576b578b-cns4q        2/2     Running   0          84s
messagebus-559bb6896c-w24s2          1/1     Running   0          84s
minio-7b4d8ddbd8-lbvpj               1/1     Running   0          14m
mysql-7cbb9c9586-scv9g               1/1     Running   0          29m
proxy-5f67f7fd7c-n8twg               1/1     Running   0          84s
registry-6d64cf7dc9-fhtsl            1/1     Running   0          29m
registry-facade-sznt7                1/1     Running   0          67s
server-7d94d9c9f6-xbpdw              1/1     Running   0          84s
ws-daemon-jjnjr                      1/1     Running   0          77s
ws-manager-68ccf9885c-nhnz6          1/1     Running   0          84s
ws-manager-bridge-74ff44975d-5ptdx   1/1     Running   0          84s
ws-proxy-8597994c89-8djvq            1/1     Running   0          83s
ws-scheduler-6865698f45-7khgm        1/1     Running   0          83s

ではgitpodにアクセスしてみますが、まず色々名前解決できないといけません。
僕の場合はDnsmasqを以下の設定としました。

[centos@dns ~]$ sudo cat /etc/dnsmasq.conf
no-hosts
addn-hosts=/etc/hosts_dnsmasq
log-queries
log-facility=/var/log/dnsmasq/dnsmasq.log
port=53
bogus-priv
resolv-file=/etc/dnsmasq_resolv.conf
strict-order
domain-needed
cache-size=0
address=/gitpod.tsuchinokometal.com/192.168.10.240
address=/ws.gitpod.tsuchinokometal.com/192.168.10.240
address=/example.tsuchinokometal.com/192.168.10.210

では僕の環境ではhttps://gitpod.tsuchinokometal.comにブラウザでアクセスします。
ご自身のドメインに書き換えてください。

以下の画面が表示されたら成功です。

gitpod_01.png

GitLab連携

こちら の手順を進めます。

GitLabのホスト名を入力します。

gitpod_02.png

次の画面で表示されるRedirect URLをコピーして、
GitLabでアプリケーションを作成します。

gitpod_03.png

作成されたApplication IDとSecretをコピーします。

gitpod_04.png

GitPod設定画面で貼り付けます。

gitpod_05.png

Connectをクリックします。

gitpod_06.png

Authorizeをクリックします。

gitpod_07.png

Accept to continueをクリックします。

gitpod_08.png

これで設定は完了のようです。

gitpod_09.png

では早速GitPodを起動してみましょう。

gitpod_10.png

初回はかなり時間かかります。
しばらく放っておいた方がいいです。

gitpod_11.png

僕の場合、ここでヒントの少ないエラーが発生して進めませんでした。

cannot initialize workspace: cannot initialize workspace: content initializer failed
gitpod_12.png

色々悩んだ結果、HelmのUpdateではなく、一旦削除して再インストールすると改善しました。
Updateだけでは足りない場合があるようです。

ubuntu@gitpod:~$ helm delete gitpod
ubuntu@gitpod:~$ helm install -f values.custom.yaml gitpod gitpod.io/gitpod --version=0.8.0

また初期設定などをやり直して再チャレンジ。

gitpod_13.png

ドキドキしながら待ちます。

gitpod_14.png

起動した!
READMEしかないですが、ちゃんとクローンされているようですね。

gitpod_15.png

起動してみたところ、ちょっとGitPodの起動が遅いと感じました。
まぁ1台の物理サーバーで全部起動しているのでしょうがないですかね。
仕事で使うならクラスターはそこその処理能力のものを準備した方が良さそうです。

あと、突然ブラウザでアクセスできなくなることがありましたが、
それはブラウザのキャッシュを削除したら直りました。
もし発生したらお試しください。

さてこれから仕事で使えるか、色々試してみようと思います。