2023-08-28

openshift 4.8 安裝後調整

一.新增自動上 letsencrypt 功能:

這樣以後在router加個annotation ->  kubernetes.io/tls-acme : true 就會自動上letsencrypt憑證了。
參考:
https://developer.ibm.com/tutorials/secure-red-hat-openshift-routes-with-lets-encrypt/
https://github.com/tnozicka/openshift-acme/tree/master/deploy#cluster-wide
https://www.redhat.com/en/blog/dynamic-ssl-certificates-using-letsencrypt-openshift

就算不是cluster admin,也可以在自已的專案內使用,比較麻煩的就是每個專案都要佈署進去一次,這裡採的是用cluster wide的方法,必須是cluster admin才行,這樣後以每個使用者就不用自已再做一次,直接上annotation就行。

做法(使用cluster admin):
1.用cluster admin -> oc login
2.執行以下命令:

$ oc new-project acme-operator
$ oc apply -fhttps://raw.githubusercontent.com/tnozicka/openshift-acme/master/deploy/single-namespace/{role,serviceaccount,issuer-letsencrypt-live,deployment}.yaml
$ oc create rolebinding openshift-acme --role=openshift-acme --serviceaccount="$( oc project -q ):openshift-acme" --dry-run -o yaml | oc apply -f -


二.設定default sotrage class:

這樣以後佈署服務時,有掛volume的話,就不用再手動指定storage class,而會自動使用預設的storage class,否則之前都要手動改PVC的yml去指定:
$ sed -i '/spec:/a\  storageClassName: managed-nfs-storage' configs/*-persistentvolumeclaim.yaml

參考
https://www.goglides.dev/bkpandey/how-to-configure-default-storage-class-in-openshift-2oj4

$oc patch storageclass managed-nfs-storage -p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "true"}}}'


三.掛載 image registry 的 PV (persistent volume):

預設佈署完 OCP內建的 image registry是沒有作用的,因為沒有指定PV(persistent volume)給他,這樣一些功能是無法正常使用的,譬如build config (在OCP上build image),這包含了S2I (source to image)及build from dockerfile等功能,因此要先給他一個PV才能正常運作。

參考
https://www.ibm.com/docs/zh-tw/mas-cd/continuous-delivery?topic=requirements-enabling-openshift-internal-image-registry
https://access.redhat.com/documentation/en-us/openshift_container_platform/4.3/html/registry/setting-up-and-configuring-the-registry#registry-configuring-storage-baremetal_configuring-registry-storage-baremetal
https://access.redhat.com/documentation/en-us/red_hat_openshift_container_storage/4.2/html-single/managing_openshift_container_storage/index#configuring-image-registry-to-use-openshift-container-storage_rhocs

假設要掛到某個名稱為managed-nfs-storage的storage class,因為是nfs,所以要先確認nfs server上的mount option有no_wdelay 還有 root_squash (但root_squash我沒有加就是了):

# cat /etc/exports
/mnt/data *(rw,sync,no_wdelay,root_squash,insecure,fsid=0)
# systemctl restart nfs-server

再下指令:

$ oc project openshift-image-registry

$ oc create -f <(echo '{
   "apiVersion": "v1",
   "kind": "PersistentVolumeClaim",
   "metadata": {
     "name": "image-registry-storage"
   },
   "spec": {
     "storageClassName": "managed-nfs-storage",
     "accessModes": [ "ReadWriteMany" ],
     "resources": {
       "requests": { "storage": "100Gi"
     }
   }
 }
}');

================

$ oc edit configs.imageregistry.operator.openshift.io -n openshift-image-registry

======== 手動修改 ========

spec:

    managementState: Managed

storage:

      pvc:

        claim: image-registry-storage

========================

$ oc get co image-registry

===================================================

也有把PVC先掛到暫存空間的方法,但是不建議用在production的服務上:
https://serverfault.com/questions/1082295/how-to-enable-local-image-registry-on-openshift-single-node-cluster-installation

.........
  managementState: Managed
..........
  replica: 1
...........
  storage:
    emptyDir: {}

==================

之後看要不要把image registry公開到網路上(也就是建立一個route),可以用預設的DefaultRoute或是自已手動建一個route:
https://access.redhat.com/documentation/en-us/openshift_container_platform/4.8/html/registry/securing-exposing-registry

然後讓要可以登入的使用者新增role:
https://access.redhat.com/documentation/en-us/openshift_container_platform/4.8/html/registry/accessing-the-registry#prerequisites

$ oc project openshift-image-registry
$ oc policy add-role-to-user registry-viewer <user_name>
$ oc policy add-role-to-user registry-editor <user_name>

之後登入(用docker或podman都行)

$ oc whoami -t #先取得登入token,注意不是直接打使用者密碼登入!
$ podman login image-registry.your-opensfhit.domain
Username:<username>
Password:<剛取得的 token>

四.將ingress operator的default controller改用proxy protocol (haproxy也要同時修改):

這樣的好處是pod服務內的程式不但可以從X-Forward-For抓到真實的來源IP,也可以在router下annotation做IP的白名單whitelist,真的是太方便了!

參考:
https://docs.openshift.com/container-platform/4.8/networking/ingress-operator.html#nw-ingress-controller-configuration-proxy-protocol_configuring-ingress
https://www.haproxy.com/documentation/hapee/latest/load-balancing/client-ip-preservation/enable-proxy-protocol/

指令:
$ oc -n openshift-ingress-operator edit ingresscontroller/default

找到最上層的spec (注意不要加到status去了),加入:

  spec:
    endpointPublishingStrategy:
      hostNetwork:
        protocol: PROXY
      type: HostNetwork

再到 haproxy 的機器,修改 /etc/haproxy/haproxy.cfg,在 listen 或 backend 端的80, 443的server instruction加入send-proxy,mode tcp不用動,這樣就會以proxy protocol溝通(也就是每個連線會加入proxy協定自已的特殊header):

listen ingress-router-443
  bind *:443
  mode tcp
  balance source
  server worker0 worker0.example.com:443 check inter 1s send-proxy
  server worker1 worker1.example.com:443 check inter 1s send-proxy
  server worker2 worker2.example.com:443 check inter 1s send-proxy

接下來可以佈署一個簡單的網頁服務,印出header看看有沒有X-Forwarded-For帶真實IP。

router做白名單的方法:

https://docs.openshift.com/container-platform/4.8/networking/routes/route-configuration.html#nw-route-specific-annotations_route-configuration

在要限制IP的router加入annotation(IP或網段都可以,用space隔開):
haproxy.router.openshift.io/ip_whitelist:  168.85.1.1 203.22.5.0/8

================================

另外關於佈署服務:

一、imagePullPolicy

https://docs.openshift.com/container-platform/4.8/openshift_images/managing_images/image-pull-policy.html

規則如下:

If the tag is latest, OpenShift Container Platform defaults imagePullPolicy to Always.
Otherwise, OpenShift Container Platform defaults imagePullPolicy to IfNotPresent.

但是呢,實際上並不是這麼回事,即使image的tag是latest,他還是不會自動拉新的image,還是會一直使用cache裡面的,真的很困擾,因此每次佈署時,最好手動改一下deploy檔:

$ sed -i '/\          image:/a\          imagePullPolicy: Always' configs/*-deployment.yaml

二、kompose轉換為opensfhit的佈署檔而不是k8s

kompose convert加參數--provider openshift並用 oc apply -f 佈署

https://kubernetes.io/docs/tasks/configure-pod-container/translate-compose-kubernetes/#openshift-kompose-convert-example

但實際上用會有些轉不太完整,

如image stream的設定檔*.imagestream.yaml要手動加 spec.tag.name(image的tag號,應該是bug)

不支援docker compose file的 extra_hosts 參數,得要自已在*.deploymentconfig.yaml的spec.template.spec 手動加:

hostAliases:
        - ip: "100.1.2.3"
          hostnames:
          - "myhost.domain.com"


反而不加--provider openshift參數並改用 kubectl apply -f 倒是沒啥問題...


三、讓container集中在一個pod,而不是一個container就一個pod

可以在kompose convert加參數 --multiple-container-mode 試試

https://github.com/kubernetes/kompose/pull/1394?source=post_page-----20ce5313be1e--------------------------------

四、關於pod運行時的一些權限問題

https://ithelp.ithome.com.tw/articles/10243781

由於OCP對容器的限制比k8s嚴格,不准容器內直接用root(uid= 0 或 root)去執行,而是會隨機給一個UID,但給予的GID是屬於root group的(gid= 0 或 root),因此寫dockerfile時,最好把會動到的目錄(如寫入log 或 tmp 或安裝 plugin檔等的目錄,就是有可能寫入或動到檔案的地方):

RUN chgrp -R 0 /some/directory \
  && chmod -R g+rwX /some/directory

docker compose file的service 可以加入user來指定使用者跟群組:
https://docs.docker.com/compose/compose-file/05-services/#user
如在service下面指定
user: 0:0

user: root:root
但這在 openshift 是沒用的,因為就是不允許 root 去跑...

那如果硬要使用image預設指定的user去跑呢?那就要先在專案建一個SA(service account),再把anyuid這個scc policy指定給SA,然後在專案config寫入指定SA:

#用 admin 執行 (一次就好)
oc project my-project
oc create sa my-sa
oc adm policy add-scc-to-user anyuid -z my-sa

#用 user 執行patch (每次重deploy都要)
oc patch dc gitlab -p '{"spec":{"template":{"spec":{"serviceAccountName": "gitlab-sa"}}}}'

#或手動加到deploymentconfig.yaml (每次重deploy都要)

spec:
  template:
    spec:
      serviceAccountName: my-sa

五、關於 coredns 查詢dns時的問題

用以下指令,可發現 cluster的dns ip 固定為 172.30.0.10:
oc get svc -n openshift-dns dns-default -o wide

用172.30.0.10去查,有時會出現 "truncated, retrying in tcp mode":
dig xxx.test.domain @172.30.0.10
nslookup xxx.test.domain 172.30.0.10

再根據以下二篇文章說明,可知dns查詢時,若是回傳的資訊量太大(>512),可能就會由UDP查詢變為TCP查詢,因此會出現 "truncated, retrying in tcp mode"是正常的,不是壞掉:
https://bugzilla.redhat.com/show_bug.cgi?id=2043046#c3
https://bugzilla.redhat.com/show_bug.cgi?id=2062307#c14

因此去檢查upstream的dns server時,發現 53/TCP 竟然沒監聽,只剩下 53/UDP,因此把bind給重啟就好了,只是怎麼會掛掉…蠻神奇的。

六、Ingress Controller 數量不夠的問題

參照:
https://access.redhat.com/discussions/5490621#comment-2288691
https://access.redhat.com/documentation/zh-tw/openshift_container_platform/4.5/html/networking/configuring-ingress-controller#nw-ingress-controller-configuration_configuring-ingress

單位的openshift平台配置了六個node,master x 3(作為api的管理pod用),worker x 3(作為使用者專案產生的pod運行)。


某天查haproxy的log時,發現有以下訊息:
localhost haproxy[3679]: Server ingress-router-80/worker0 is DOWN, reason: Layer4 connection problem, info: "Connection refused", check duration: 0ms. 2 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.

表示worker0的haproxy(也是就ingress controller)沒在跑,因此80/443都被refused,netstate去檢查80/443也沒有程式在監聽,用以下指令查目前的ingress controller的replicas數量:

$ oc get -n openshift-ingress-operator ingresscontrollers/default -o jsonpath='{$.status.availableReplicas}'

發現數量只有2,但有3台worker,數量當然不夠,因此增加replica的數量:

$ oc patch -n openshift-ingress-operator ingresscontroller/default --patch '{"spec":{"replicas": 3}}' --type=merge

設定haproxy log的方法:https://linuxconfig.org/install-and-configure-haproxy-on-redhat-8