openshift 4.10, single node with customized partition

做POC经常有这样的问题:客户的主机上,就一块1T SSD,我们知道,ocp 默认安装,会占用这第一块硬盘,分4个分区,其中root分区几乎占满整个硬盘。但是其实ocp运行的时候,只会用到100G左右,那么这1T SSD的大部分就浪费掉了。我们希望能从这个1T的硬盘中,分出来800G,给存储解决方案用,比如ceph/odf,那么怎么在安装的过程中,定制installer,让他给我们多分出来第5个分区呢?

本文描述,如何在single node openshift上,如果是单独硬盘的话,如何在这个硬盘上,多分出来几个分区,来做数据分区。

这个在某些资源有限PoC场景下,会很有用,比如需要在单硬盘single node上启动ceph.

本文,有一个背景知识,或者是前导实验,就是如何部署一个普通的single node openshift

内部安装逻辑图如下:

视频讲解

additional steps during sno install


# download yq and install
mkdir tmp; cd tmp
wget https://github.com/mikefarah/yq/releases/download/v4.25.1/yq_linux_amd64.tar.gz
tar -zxvf yq_linux_amd64.tar.gz
install yq_linux_amd64 /usr/local/bin/yq

# calcuate a password
# VAR_PWD=`podman run -ti --rm quay.io/coreos/mkpasswd --method=yescrypt redhat`
# $y$j9T$UCg7ef5in/0aw0C2ZqSFo.$n8gC9.kDzWwlq0GmXKDVH8KUuGNdj7l6tnAsR4RZaG5

VAR_PWD_HASH="$(python3 -c 'import crypt,getpass; print(crypt.crypt("redhat"))')"

# # https://docs.fedoraproject.org/en-US/fedora-coreos/storage/#_setting_up_separate_var_mounts
# cat << EOF > /data/sno/root-partition.bu
# variant: openshift
# version: 4.8.0
# metadata:
#   name: root-storage
#   labels:
#     machineconfiguration.openshift.io/role: master
# storage:
#   disks:
#     - device: /dev/vda
#       wipe_table: false
#       partitions:
#         - number: 4
#           label: root
#           size_mib: $(( 120 * 1024 ))
#           resize: true
#         - label: data_odf_lvm
#           size_mib: 0
# EOF

# butane /data/sno/root-partition.bu -r -o /data/install/partition-ric.ign

# # merge the 2 ignition files
# jq -s '.[0] * .[1]' /data/install/iso.ign /data/install/partition-ric.ign | jq -c . > /data/install/iso.ign.new

# /bin/cp -f /data/install/iso.ign.new  /data/install/iso.ign

# https://github.com/openshift/installer/blob/master/data/data/bootstrap/bootstrap-in-place/files/opt/openshift/bootstrap-in-place/master-update.fcc
# cat iso.ign | jq ' .storage.files[] | select ( .path == "/opt/openshift/bootstrap-in-place/master-update.fcc" ) ' | jq -r .contents.source | sed 's/.*base64,//g' | base64 -d > /data/install/master-update.fcc



cat << EOF > /data/install/root-partition.fc
variant: fcos
version: 1.3.0
#   !!! do not include passwd / users in production system !!!
passwd:
  users:
    - name: wzh
      password_hash: $VAR_PWD_HASH
      system: true
      ssh_authorized_keys:
        - $NODE_SSH_KEY
      groups:
        - adm
        - wheel
        - sudo
        - systemd-journal
storage:
  disks:
    - device: /dev/vda
      wipe_table: false
      partitions:
        - number: 4
          label: root
          size_mib: $(( 120 * 1024 ))
          resize: true
        # - label: data_01
        #   size_mib: $(( 5 * 1024 ))
        - label: data_odf_lvm
          size_mib: 0
EOF

butane /data/install/root-partition.fc -r -o /data/install/partition-ric.ign


cat << EOF > /data/sno/root-partition.bu
variant: openshift
version: 4.9.0
metadata:
  labels:
    machineconfiguration.openshift.io/role: master
  name: 99-zzz-master-static-hostname
storage:
  files:
    - path: /opt/openshift/partition-ric.ign
      mode: 0644
      overwrite: true
      contents:
        local: partition-ric.ign

EOF


# yq '. *= load("/data/install/master-update.fcc")' /data/install/root-partition.fc > /data/install/root-partition.fcc

# config_source=$(cat /data/install/root-partition.fcc | python3 -c "import sys, urllib.parse; print(urllib.parse.quote(''.join(sys.stdin.readlines())))"  )
# VAR_FCC_FILE="data:text/plain,${config_source}"

butane -d /data/install /data/sno/root-partition.bu > /data/sno/disconnected/99-zzz-master-root-partition.yaml
get_file_content_for_ignition "/opt/openshift/partition-ric.ign" "/data/sno/disconnected/99-zzz-master-root-partition.yaml"
VAR_99_master_fcc=$RET_VAL
VAR_99_master_fcc_2=$RET_VAL_2


cat iso.ign | jq ' .storage.files[] | select ( .path == "/usr/local/bin/bootstrap-in-place.sh" ) ' | jq -r .contents.source | sed 's/.*base64,//g' | base64 -d > /data/install/bootstrap-in-place.sh

# try to replace

# merge the 2 ignition files
cat << EOF > /data/install/bootstrap-in-place.sh.patch
jq -s '.[0] * .[1]' /opt/openshift/master.ign /opt/openshift/partition-ric.ign | jq -c . > /opt/openshift/master.ign.new
/bin/cp -f /opt/openshift/master.ign.new /opt/openshift/master.ign
EOF

# https://stackoverflow.com/questions/26141347/using-sed-to-insert-file-content-into-a-file-before-a-pattern
sed $'/touch master-ignition.done/{e cat \/data\/install\/bootstrap-in-place.sh.patch\n}' /data/install/bootstrap-in-place.sh > /data/install/bootstrap-in-place.sh.new

cat << EOF > /data/sno/bootstrap-in-place.bu
variant: openshift
version: 4.9.0
metadata:
  labels:
    machineconfiguration.openshift.io/role: master
  name: 99-zzz-master-bootstrap-in-place
storage:
  files:
    - path: /usr/local/bin/bootstrap-in-place.sh
      mode: 0555
      overwrite: true
      contents:
        local: bootstrap-in-place.sh.new

EOF

butane -d /data/install /data/sno/bootstrap-in-place.bu > /data/sno/disconnected/99-zzz-master-bootstrap-in-place.yaml
get_file_content_for_ignition "/usr/local/bin/bootstrap-in-place.sh" "/data/sno/disconnected/99-zzz-master-bootstrap-in-place.yaml"
VAR_99_master_bootstrap_sh=$RET_VAL
VAR_99_master_bootstrap_sh_2=$RET_VAL_2

cat iso.ign | jq ' del ( .storage.files[] | select ( .path == "/usr/local/bin/bootstrap-in-place.sh" ) )' > /data/install/iso.ign.new

# cat iso.ign | jq ' .storage.files[] | select ( .path == "/usr/local/bin/bootstrap-in-place.sh" ) ' | jq -r .contents.source 

cat /data/install/iso.ign.new \
  | jq --argjson VAR "$VAR_99_master_fcc_2" '.storage.files += [$VAR] ' \
  | jq --argjson VAR "$VAR_99_master_bootstrap_sh_2" '.storage.files += [$VAR] ' \
  | jq -c . \
  > /data/install/iso.ign

# cat iso.ign | jq ' .storage.files[] | select ( .path == "/opt/openshift/bootstrap-in-place/master-update.fcc" ) ' | jq -r .contents.source 
# cat iso.ign | jq ' .storage.files[] | select ( .path == "/opt/openshift/partition-ric.ign" ) ' | jq -r .contents.source 

check the result

ssh -tt core@192.168.7.13 -- lsblk
# NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
# sr0     11:0    1  1024M  0 rom
# vda    252:0    0   400G  0 disk
# ├─vda1 252:1    0     1M  0 part
# ├─vda2 252:2    0   127M  0 part
# ├─vda3 252:3    0   384M  0 part /boot
# ├─vda4 252:4    0   120G  0 part /sysroot
# └─vda5 252:5    0 279.5G  0 part

local storage operator

我们有了很多分区,那么赶快来测试一下如何把他们变成 PV 吧

cat << EOF > /data/install/local-storage.yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: openshift-local-storage
  annotations:
    workload.openshift.io/allowed: management
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: openshift-local-storage
  namespace: openshift-local-storage
spec:
  targetNamespaces:
  - openshift-local-storage
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: local-storage-operator
  namespace: openshift-local-storage
spec:
  channel: "stable"
  installPlanApproval: Manual
  name: local-storage-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace
EOF
oc create -f /data/install/local-storage.yaml


cat << EOF > /data/install/local-storage-lv.yaml
apiVersion: "local.storage.openshift.io/v1"
kind: "LocalVolume"
metadata:
  name: "local-disks"
  namespace: "openshift-local-storage" 
spec:
  nodeSelector: 
    nodeSelectorTerms:
    - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - acm-demo-hub-master
  storageClassDevices:
    - storageClassName: "local-sc" 
      volumeMode: Filesystem 
      fsType: xfs 
      devicePaths: 
        - /dev/vda5
EOF
oc create -f /data/install/local-storage-lv.yaml


我们创建pod,创建和使用pvc,然后弄点数据,然后删掉pod,删掉pvc。然后重新创建pod,创建和使用pvc,看看里面的数据是否会清空。

cat << EOF >> /data/install/pvc-demo.yaml
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: local-pvc-demo
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem 
  resources:
    requests:
      storage: 2Gi 
  storageClassName: local-sc 
---
kind: Pod
apiVersion: v1
metadata:
  annotations:
  name: demo1
spec:
  nodeSelector:
    kubernetes.io/hostname: 'acm-demo-hub-master'
  restartPolicy: Always
  containers:
    - name: demo1
      image: >- 
        quay.io/wangzheng422/qimgs:centos7-test
      env:
        - name: key
          value: value
      command: 
        - sleep
        - infinity
      imagePullPolicy: Always
      volumeMounts:
        - mountPath: /data
          name: demo 
          readOnly: false
  volumes:
    - name: demo 
      persistentVolumeClaim:
        claimName: local-pvc-demo 
EOF
oc create -n default -f /data/install/pvc-demo.yaml

install lvm operator

lvm operator dose NOT work.

tips

cat iso.ign | jq .storage.files[].path | grep fcc
# "/opt/openshift/bootstrap-in-place/master-update.fcc"

cat iso.ign | jq ' .storage.files[] | select ( .path == "/opt/openshift/bootstrap-in-place/master-update.fcc" ) ' | jq -r .contents.source | sed 's/.*base64,//g' | base64 -d
# variant: fcos
# version: 1.1.0
# ignition:
#   config:
#     merge:
#       - local: original-master.ign
# storage:
#   trees:
#     - local: kubernetes/bootstrap-configs
#       path: /etc/kubernetes/bootstrap-configs
#     - local: tls/
#       path: /etc/kubernetes/bootstrap-secrets
#     - local: etcd-bootstrap/etc-kubernetes/static-pod-resources/etcd-member/
#       path: /etc/kubernetes/static-pod-resources/etcd-member
#     - local: etcd-data
#       path: /var/lib/etcd
#   files:
#     - path: /etc/kubernetes/bootstrap-secrets/kubeconfig
#       contents:
#         local: auth/kubeconfig-loopback
#     - path: /etc/kubernetes/manifests/etcd-pod.yaml
#       contents:
#         local: etcd-bootstrap/etc-kubernetes/manifests/etcd-member-pod.yaml
#     - path: /etc/kubernetes/manifests/kube-apiserver-pod.yaml
#       contents:
#         local: bootstrap-manifests/kube-apiserver-pod.yaml
#     - path: /etc/kubernetes/manifests/kube-controller-manager-pod.yaml
#       contents:
#         local: bootstrap-manifests/kube-controller-manager-pod.yaml
#     - path: /etc/kubernetes/manifests/kube-scheduler-pod.yaml
#       contents:
#         local: bootstrap-manifests/kube-scheduler-pod.yaml
#     - path: /usr/local/bin/bootstrap-in-place-post-reboot.sh
#       contents:
#         local: bootstrap-in-place/bootstrap-in-place-post-reboot.sh
#       mode: 0555
#     - path: /var/log/log-bundle-bootstrap.tar.gz
#       contents:
#         local: log-bundle-bootstrap.tar.gz
#     - path: /usr/local/bin/installer-masters-gather.sh
#       contents:
#         local: bin/installer-masters-gather.sh
#       mode: 0555
#     - path: /usr/local/bin/installer-gather.sh
#       contents:
#         local: bin/installer-gather.sh
#       mode: 0555
# systemd:
#   units:
#     - name: bootkube.service
#       enabled: true
#       contents: |
#         [Unit]
#         Description=Bootkube - bootstrap in place post reboot
#         Wants=kubelet.service
#         After=kubelet.service
#         ConditionPathExists=/etc/kubernetes/bootstrap-secrets/kubeconfig
#         [Service]
#         Type=oneshot
#         ExecStart=/usr/local/bin/bootstrap-in-place-post-reboot.sh
#         RestartSec=5s
#         [Install]
#         WantedBy=multi-user.target

cat iso.ign | jq ' .storage.files[] | select ( .path == "/usr/local/bin/bootstrap-in-place.sh" ) ' | jq -r .contents.source | sed 's/.*base64,//g' | base64 -d
# ......

#   echo "Adding bootstrap control plane and bootstrap installer-gather bundle to master ignition"
#   bootkube_podman_run \
#     --rm \
#     --privileged \
#     --volume "$PWD:/assets:z" \
#     --volume "/usr/local/bin/:/assets/bin" \
#     --volume "/var/lib/etcd/:/assets/etcd-data" \
#     --volume "/etc/kubernetes:/assets/kubernetes" \
#     "${CLUSTER_BOOTSTRAP_IMAGE}" \
#     bootstrap-in-place \
#     --asset-dir /assets \
#     --input /assets/bootstrap-in-place/master-update.fcc \
#     --output /assets/master.ign

#   touch master-ignition.done
#   record_service_stage_success
# fi

# https://github.com/openshift/cluster-bootstrap
cd /data/install

podman run --rm -it  \
    --privileged \
    --volume "$PWD:/assets:z" \
    --volume "/usr/local/bin/:/assets/bin" \
    --volume "/var/lib/etcd/:/assets/etcd-data" \
    --volume "/etc/kubernetes:/assets/kubernetes" \
    quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:c29cb321d7ac72d86a86ba4a74a0774ed2ebf9910d65c1805245a17d7b005b88 \
    bootstrap-in-place \
    --asset-dir /assets \
    --input /assets/bootstrap-in-place/master-update.fcc \
    --output /assets/master.ign

lsblk -o PARTUUID,NAME,FSTYPE,LABEL,UUID,MOUNTPOINT
# PARTUUID                             NAME   FSTYPE LABEL      UUID                                 MOUNTPOINT
#                                      sr0
#                                      vda
# e23d3123-1d83-4665-8b0f-1c39f8e8f533 ├─vda1
# ed26d305-052e-4148-9b44-05357053742a ├─vda2 vfat   EFI-SYSTEM 1533-24B8
# ae634b25-a5b9-4667-85ce-119455a92e53 ├─vda3 ext4   boot       85555068-e37d-4773-837c-d279550eb818 /boot
# ef1b4117-0c2d-4f53-abd4-d3019ecf267e ├─vda4 xfs    root       936512ae-5449-4a2f-808e-1c698859c877 /sysroot
# e7b459fb-f2e1-43c9-b638-c732898eedf5 ├─vda5
# 9f0f85c7-51c6-4f2a-b7b7-c8ea3131fb32 └─vda6

end


Array.from(document.querySelectorAll("div[class='catalog-tile-pf-title']")).forEach(txt => console.log(txt.html()));