All in one deployment for Kubernetes cluster in the hard Way
Edit me

Kubernetes All-in-One Deployment in the Hard Way

=====

Env

Item Explanation Value in config config file
cluster-name   ecs-matrix-k8s-cluster-all-in-one admin.kubeconfig, kubelet.kubeconfig, kube-proxy.kubeconfig
service-cluster-ip-range A CIDR IP range from which to assign service cluster IPs 10.32.0.0/24 kube-apiserver.service
cluster-cidr CIDR Range for Pods in cluster 10.64.1.0/24 kube-controller-manager.service, kube-proxy-config.yaml
podCIDR   10.64.1.0/24 10-bridge.conf, kubelet-config.yaml

CA

Config

# cat <<EOF > /etc/pki/tls/openssl.cnf
HOME                    = .
RANDFILE                = \$ENV::HOME/.rnd
oid_section             = new_oids

[ new_oids ]
tsa_policy1 = 1.2.3.4.1
tsa_policy2 = 1.2.3.4.5.6
tsa_policy3 = 1.2.3.4.5.7

[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]
dir             = /etc/pki/CA           # Where everything is kept
certs           = \$dir/certs           # Where the issued certs are kept
crl_dir         = \$dir/crl             # Where the issued crl are kept
database        = \$dir/index.txt       # database index file.
                                        # several ctificates with same subject.
new_certs_dir   = \$dir/newcerts                # default place for new certs.
certificate     = \$dir/ca.crt          # The CA certificate
serial          = \$dir/serial          # The current serial number
crlnumber       = \$dir/crlnumber       # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = \$dir/ca.crl          # The current CRL
private_key     = \$dir/private/ca.key   # The private key
RANDFILE        = \$dir/private/.rand   # private random number file
x509_extensions = usr_cert              # The extentions to add to the cert
name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options
default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha256                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering
policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
default_bits            = 2048
default_md              = sha256
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert

string_mask = utf8only

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = XX
countryName_min                 = 2
countryName_max                 = 2
stateOrProvinceName             = State or Province Name (full name)
localityName                    = Locality Name (eg, city)
localityName_default            = Default City
0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Default Company Ltd
organizationalUnitName          = Organizational Unit Name (eg, section)
commonName                      = Common Name (eg, your name or your server\'s hostname)
commonName_max                  = 64
emailAddress                    = Email Address
emailAddress_max                = 64

[ req_attributes ]
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20
unstructuredName                = An optional company name

[ usr_cert ]
basicConstraints=CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = CA:true

[ crl_ext ]
authorityKeyIdentifier=keyid:always

[ proxy_cert_ext ]
basicConstraints=CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo

[ tsa ]
default_tsa = tsa_config1       # the default TSA section

[ tsa_config1 ]
dir             = ./demoCA              # TSA root directory
serial          = \$dir/tsaserial       # The current serial number (mandatory)
crypto_device   = builtin               # OpenSSL engine to use for signing
signer_cert     = \$dir/tsacert.pem     # The TSA signing certificate
                                        # (optional)
certs           = \$dir/cacert.pem      # Certificate chain to include in reply
                                        # (optional)
signer_key      = \$dir/private/tsakey.pem # The TSA private key (optional)
default_policy  = tsa_policy1           # Policy if request did not specify it
                                        # (optional)
other_policies  = tsa_policy2, tsa_policy3      # acceptable policies (optional)
digests         = sha1, sha256, sha384, sha512  # Acceptable message digests (mandatory)
accuracy        = secs:1, millisecs:500, microsecs:100  # (optional)
clock_precision_digits  = 0     # number of digits after dot. (optional)
ordering                = yes   # Is ordering defined for timestamps?
                                # (optional, default: no)
tsa_name                = yes   # Must the TSA name be included in the reply?
                                # (optional, default: no)
ess_cert_id_chain       = no    # Must the ESS cert id chain be included?
                                # (optional, default: no)
EOF        

create a file to indicate the next certificate serial number to be issued

# echo 01 > /etc/pki/CA/serial

Create an empty certificate index

# touch /etc/pki/CA/index.txt

Generate CA Private key

# (umask 077; openssl genrsa -out /etc/pki/CA/private/ca.key -des3 2048)

output

Generating RSA private key, 2048 bit long modulus
...................................+++
......................+++
e is 65537 (0x10001)
Enter pass phrase for /etc/pki/CA/private/ca.key:
Verifying - Enter pass phrase for /etc/pki/CA/private/ca.key:

Generate CA public Cert

# openssl req -new -x509 -key /etc/pki/CA/private/my-ca.key -days 365 > /etc/pki/CA/my-ca.crt

output

Enter pass phrase for /etc/pki/CA/private/my-ca.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]: CN
State or Province Name (full name) [New York]: BJ
Locality Name (eg, city) [New York]: Beijing
Organization Name (eg, company) [Example]: Matrix
Organizational Unit Name (eg, section) []: Matrix
Common Name (eg, your name or your server's hostname) []:ecs-matrix-k8s-cluster-2
Email Address []:root@ecs-matrix-k8s-cluster-2

kube-apiserver

Cert

config

The Kubernetes API server is automatically assigned the kubernetes internal dns name, which will be linked to the first IP address (10.32.0.1) from the address range of service-cluster-ip-range(10.32.0.0/24) reserved for internal cluster services

# cat <<EOF > apiserver.cnf
[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]
dir             = /etc/pki/CA           # Where everything is kept
certs           = \$dir/certs            # Where the issued certs are kept
crl_dir         = \$dir/crl              # Where the issued crl are kept
database        = \$dir/index.txt        # database index file.
new_certs_dir   = \$dir/newcerts         # default place for new certs.

certificate     = \$dir/ca.crt           # The CA certificate
serial          = \$dir/serial           # The current serial number
crlnumber       = \$dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = \$dir/ca.crl           # The current CRL
private_key     = \$dir/private/ca.key   # The private key
RANDFILE        = \$dir/private/.rand    # private random number file

x509_extensions = usr_cert              # The extentions to add to the cert

name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha256                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering

policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ usr_cert ]
basicConstraints=CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
subjectAltName = @alt_names

[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.svc.cluster.local
DNS.6 = ecs-matrix-k8s-cluster-2
IP.1 = 127.0.0.1
IP.2 = 10.32.0.1
IP.3 = 172.16.1.180
EOF
Private Key
# openssl genrsa -out apiserver.key 2048
Cert Request
# openssl req -new -out apiserver.csr -key apiserver.key -config apiserver.cnf

# openssl req -in apiserver.csr -noout -text
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=CN, ST=BJ, L=Beijing, O=Matrix, OU=Matrix, CN=kubernetes/emailAddress=root@ecs_matrix_k8s_cluster_2
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:f3:48:fa:3f:01:e2:89:a6:72:e1:df:5b:bd:33:
                    54:65:b0:75:5b:1d:24:08:30:29:52:2f:47:07:b3:
                    47:47:80:bf:22:6c:1f:80:75:17:7f:2f:ff:81:ad:
                    2b:c5:28:2d:4b:d9:dd:e7:94:8a:06:4e:94:c5:0b:
                    00:5a:13:07:61:58:9d:4d:51:c8:17:ae:d3:f7:bd:
                    6d:32:09:50:04:85:7f:f4:4e:21:6f:81:20:42:24:
                    ac:89:96:4f:30:6c:65:7b:92:dd:7e:0e:55:06:df:
                    41:6c:b7:a5:e3:e2:5c:4f:62:cf:24:47:1d:fe:65:
                    1e:6f:90:69:38:8a:30:b7:7a:80:19:7c:3f:cd:76:
                    b8:f8:57:90:4e:ce:e6:8b:fd:d3:07:fd:74:d6:96:
                    5d:21:ad:e6:38:6d:3b:d0:11:45:c4:25:62:97:fb:
                    a4:28:21:15:da:05:bd:36:f8:0a:e6:1a:04:d5:bb:
                    a0:d4:62:36:49:17:fd:ca:71:57:26:c0:73:6e:49:
                    94:7d:5a:27:17:2f:2b:ca:e5:df:13:e1:77:c8:9a:
                    7e:4b:cd:ec:1a:cb:51:4a:f0:c5:9b:37:97:10:e2:
                    cd:ea:bf:4f:11:a9:75:8e:87:6a:da:c5:e6:d2:c7:
                    27:3c:33:e4:86:21:da:1b:14:09:0c:48:67:1a:66:
                    f6:13
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Key Usage:
                Digital Signature, Non Repudiation, Key Encipherment, Key Agreement

    Signature Algorithm: sha256WithRSAEncryption
         ac:86:32:5c:05:fe:be:39:ca:55:7d:5a:74:7a:cb:df:6e:a4:
         b1:a5:f7:c6:12:c9:7e:03:e9:98:a9:79:7b:ee:a6:fc:41:e8:
         41:09:2e:c2:71:73:5a:26:71:9c:66:36:07:8d:db:52:89:5a:
         8a:aa:84:3f:a0:f2:44:87:48:ca:32:d3:5e:6f:0a:7b:61:fd:
         51:dc:b6:7f:e8:0e:3c:6c:75:4e:2b:06:0d:bd:9c:e4:15:ac:
         0b:c4:df:7f:d1:6e:12:48:2f:da:ff:0d:db:7c:f2:ae:77:05:
         99:0b:ae:47:be:51:20:56:18:72:73:fb:53:e3:06:72:50:47:
         57:1b:23:7a:bb:d5:50:80:45:09:5d:3d:97:5b:3b:29:ae:22:
         94:e3:33:fd:95:58:2f:1d:2a:59:d8:96:e7:bb:45:b3:6c:1c:
         eb:7a:96:ad:f9:5e:3f:c8:74:12:9c:7b:eb:6a:7d:84:e6:42:
         f0:91:3f:ce:24:da:64:e6:3a:c0:3c:21:b4:09:cb:4c:82:6a:
         de:26:9e:5a:e7:6c:19:24:36:fe:43:fa:2c:13:4f:5e:1b:86:
         a3:c5:97:ff:fe:88:45:e2:4b:ca:b3:4a:20:25:f7:b7:03:dd:
         f0:5e:19:50:10:43:95:39:35:31:81:7c:83:10:3d:9a:c5:1e:
         ff:35:2d:dc
Public Cert
# openssl ca -in apiserver.csr -out apiserver.crt -config apiserver.cnf

etcd

Tools download

# wget  https://github.com/etcd-io/etcd/releases/download/v3.4.15/etcd-v3.4.15-linux-amd64.tar.gz

#  mkdir etcd

#  tar xvf etcd-v3.4.15-linux-amd64.tar.gz -C etcd/

#  cp -v etcd/etcd-v3.4.15-linux-amd64/etcd* /usr/local/bin/

Config

# mkdir -p /etc/etcd

# mkdir -p /var/lib/etcd

# cp /etc/pki/CA/ca.crt /etc/etcd/

# cp ~/certs/apiserver/apiserver.crt /etc/etcd/

# cp ~/certs/apiserver/apiserver.key /etc/etcd/

# HOSTNAME=$(hostname -s)

# LOCAL_IP=$(ifconfig eth0 | awk '/inet /{print $2}')

# cat <<EOF > /etc/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.com/coreos

[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \\
  --name ${HOSTNAME} \\
  --cert-file=/etc/etcd/apiserver.crt \\
  --key-file=/etc/etcd/apiserver.key \\
  --peer-cert-file=/etc/etcd/apiserver.crt \\
  --peer-key-file=/etc/etcd/apiserver.key \\
  --trusted-ca-file=/etc/etcd/ca.crt \\
  --peer-trusted-ca-file=/etc/etcd/ca.crt \\
  --peer-client-cert-auth \\
  --client-cert-auth \\
  --initial-advertise-peer-urls https://${LOCAL_IP}:2380 \\
  --listen-peer-urls https://${LOCAL_IP}:2380 \\
  --listen-client-urls https://${LOCAL_IP}:2379,https://127.0.0.1:2379 \\
  --advertise-client-urls https://${LOCAL_IP}:2379 \\
  --initial-cluster ${HOSTNAME}=https://${LOCAL_IP}:2380 \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

# systemctl daemon-reload

# systemctl enable --now etcd.service

Verify

# ETCDCTL_API=3 /usr/local/bin/etcdctl member list  --endpoints=https://127.0.0.1:2379   --cacert=/etc/etcd/ca.crt --cert=/etc/etcd/apiserver.crt   --key=/etc/etcd/apiserver.key
7a4c7b48f4bff473, started, ecs-matrix-k8s-cluster-2, https://172.16.1.180:2380, https://172.16.1.180:2379, false

kube-apiserver

Config

# mkdir /var/lib/kubernetes/

# ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)

# cat <<EOF >encryption-config.yaml 
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
         keys:
           - name: key1
             secret: ${ENCRYPTION_KEY}
      - identity: {}
EOF

# cp encryption-config.yaml /var/lib/kubernetes/

# cp /etc/etcd/ca.crt /var/lib/kubernetes/

# cp /etc/etcd/apiserver.crt /var/lib/kubernetes/

# cp /etc/etcd/apiserver.key /var/lib/kubernetes/

# cat <<EOF > /etc/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \
  --advertise-address=${LOCAL_IP} \
  --allow-privileged=true \
  --apiserver-count=3 \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-path=/var/log/audit.log \
  --authorization-mode=Node,RBAC \
  --bind-address=0.0.0.0 \
  --client-ca-file=/var/lib/kubernetes/ca.crt \
  --enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
  --etcd-cafile=/var/lib/kubernetes/ca.crt \
  --etcd-certfile=/var/lib/kubernetes/apiserver.crt \
  --etcd-keyfile=/var/lib/kubernetes/apiserver.key \
  --etcd-servers=https://${LOCAL_IP}:2379 \
  --event-ttl=1h \
  --encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.crt \
  --kubelet-client-certificate=/var/lib/kubernetes/apiserver.crt \
  --kubelet-client-key=/var/lib/kubernetes/apiserver.key \
  --runtime-config=api/all=true \
  --service-account-issuer=https://${LOCAL_IP}:6443 \
  --service-account-key-file=/var/lib/kubernetes/apiserver.crt \
  --service-account-signing-key-file=/var/lib/kubernetes/apiserver.key \
  --service-cluster-ip-range=10.32.0.0/24 \
  --service-node-port-range=30000-32767 \
  --tls-cert-file=/var/lib/kubernetes/apiserver.crt \
  --tls-private-key-file=/var/lib/kubernetes/apiserver.key \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

# systemctl daemon-reload

# systemctl enable --now kube-apiserver.service

Verify

# curl --cacert /etc/etcd/ca.crt -i https://127.0.0.1:6443/healthz
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
X-Kubernetes-Pf-Flowschema-Uid: 433f7709-03d2-4f5b-bbd6-cdc4258fa304
X-Kubernetes-Pf-Prioritylevel-Uid: 34e4c49c-2184-408b-9af2-80013b24bf49
Date: Sun, 12 Jun 2022 08:04:23 GMT
Content-Length: 2

# curl --cacert /etc/etcd/ca.crt -i https://127.0.0.1:6443/version
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Content-Type: application/json
X-Kubernetes-Pf-Flowschema-Uid: 433f7709-03d2-4f5b-bbd6-cdc4258fa304
X-Kubernetes-Pf-Prioritylevel-Uid: 34e4c49c-2184-408b-9af2-80013b24bf49
Date: Sun, 12 Jun 2022 08:05:31 GMT
Content-Length: 263

{
  "major": "1",
  "minor": "21",
  "gitVersion": "v1.21.0",
  "gitCommit": "cb303e613a121a29364f75cc67d3d580833a7479",
  "gitTreeState": "clean",
  "buildDate": "2021-04-08T16:25:06Z",
  "goVersion": "go1.16.1",
  "compiler": "gc",
  "platform": "linux/amd64"
}

admin

Tools download

# wget https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl

# cp kubectl /usr/local/bin/

Certs

Notes: O(Organization) in certs must be system:masters

Config
# cat <<EOF >admin.cnf
[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]

dir             = /etc/pki/CA           # Where everything is kept
certs           = \$dir/certs            # Where the issued certs are kept
crl_dir         = \$dir/crl              # Where the issued crl are kept
database        = \$dir/index.txt        # database index file.

new_certs_dir   = \$dir/newcerts         # default place for new certs.

certificate     = \$dir/ca.crt           # The CA certificate
serial          = \$dir/serial           # The current serial number
crlnumber       = \$dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = \$dir/ca.crl           # The current CRL
private_key     = \$dir/private/ca.key   # The private key
RANDFILE        = \$dir/private/.rand    # private random number file

x509_extensions = usr_cert              # The extentions to add to the cert

name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha256                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering

policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ usr_cert ]

basicConstraints=CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

[ req ]
distinguished_name      = req_distinguished_name

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name (full name)
localityName                    = Locality Name (eg, city)
organizationName                = Organization Name (eg, company)
organizationalUnitName          = Organizational Unit Name (eg, section)
commonName                      = Common Name (eg, your name or your server\'s hostname)
emailAddress                    = Email Address
EOF
Privete key
# openssl genrsa -out admin.key 2048
Cert Request
# openssl req -new -key admin.key -out admin.csr -config admin.cnf
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) []:Beijing
Organization Name (eg, company) []:system:masters
Organizational Unit Name (eg, section) []:Matrix
Common Name (eg, your name or your server's hostname) []:ecs-matrix-k8s-cluster-2
Email Address []:root@ecs-matrix-k8s-cluster-2
Sign Cert
# openssl ca -in admin.csr -out admin.crt -config admin.cnf
Using configuration from admin.cnf
Enter pass phrase for /etc/pki/CA/private/ca.key:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 2 (0x2)
        Validity
            Not Before: Jun 12 11:17:52 2022 GMT
            Not After : Jun 12 11:17:52 2023 GMT
        Subject:
            countryName               = CN
            stateOrProvinceName       = BJ
            organizationName          = system:masters
            organizationalUnitName    = Matrix
            commonName                = ecs-matrix-k8s-cluster-2
            emailAddress              = root@ecs-matrix-k8s-cluster-2
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                AA:53:17:2F:7A:AF:17:C8:D5:B9:90:8F:E4:0F:DE:51:8B:3A:E0:65
            X509v3 Authority Key Identifier:
                keyid:EC:90:22:63:D4:73:8D:8E:DC:59:B3:AA:76:18:70:00:A7:37:6D:9D

Certificate is to be certified until Jun 12 11:17:52 2023 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Config

# kubectl config set-cluster ecs-matrix-k8s-cluster-all-in-one \
  --certificate-authority=/etc/etcd/ca.crt \
  --embed-certs=true \
  --server=https://127.0.0.1:6443 \
  --kubeconfig=admin.kubeconfig

# kubectl config set-cluster ecs-matrix-k8s-cluster-all-in-one \
  --certificate-authority=/etc/etcd/ca.crt \
  --embed-certs=true \
  --server=https://127.0.0.1:6443 \
  --kubeconfig=admin.kubeconfig

# kubectl config set-credentials admin \
  --client-certificate=/root/certs/admin/admin.crt \
  --client-key=/root/certs/admin/admin.key \
  --embed-certs=true \
  --kubeconfig=admin.kubeconfig

# kubectl config set-context default \
  --cluster=ecs-matrix-k8s-cluster-all-in-one \
  --user=admin \
  --kubeconfig=admin.kubeconfig

# kubectl config use-context default --kubeconfig=admin.kubeconfig

# mkdir ~/.kube

# cp admin.kubeconfig ~/.kube/config

Verify

# kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:6443

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

# kubectl get clusterrolebindings cluster-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-06-11T19:49:53Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: cluster-admin
  resourceVersion: "141"
  uid: df9a70bf-4a84-4669-8329-7e2a153159c0
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:masters

kubelet

In order to be authorized by the Node authorizer, kubelets must use a credential that identifies them as being in the system:nodes group, with a username of system:node:<nodeName>. By default, nodeName is the host name as provided by hostname, or overridden via the kubelet option --hostname-override. So that, group should be aligned with O(Organization) in cert, and username aligned with CN(Common Name).
Ref: Kubernetes Using Node Authorization

Tools Download

wget \
  https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.21.0/crictl-v1.21.0-linux-amd64.tar.gz \
  https://github.com/opencontainers/runc/releases/download/v1.0.0-rc93/runc.amd64 \
  https://github.com/containernetworking/plugins/releases/download/v0.9.1/cni-plugins-linux-amd64-v0.9.1.tgz \
  https://github.com/containerd/containerd/releases/download/v1.4.4/containerd-1.4.4-linux-amd64.tar.gz \
  https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubelet

Cert

Config
# cat <<EOF >kubelet.cnf
[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]

dir             = /etc/pki/CA           # Where everything is kept
certs           = \$dir/certs            # Where the issued certs are kept
crl_dir         = \$dir/crl              # Where the issued crl are kept
database        = \$dir/index.txt        # database index file.

new_certs_dir   = \$dir/newcerts         # default place for new certs.

certificate     = \$dir/ca.crt           # The CA certificate
serial          = \$dir/serial           # The current serial number
crlnumber       = \$dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = \$dir/ca.crl           # The current CRL
private_key     = \$dir/private/ca.key   # The private key
RANDFILE        = \$dir/private/.rand    # private random number file

x509_extensions = usr_cert              # The extentions to add to the cert

name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha256                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering

policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ usr_cert ]

basicConstraints=CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
subjectAltName = @alt_names

[alt_names]
DNS.1 = ecs-matrix-k8s-cluster-2
IP.1 = 127.0.0.1
IP.2 = 172.16.1.180
EOF
Private key
# openssl genrsa -out kubelet.key 2048
Cert Request
# openssl req -new -out kubelet.csr -key kubelet.key
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:Beijing
Organization Name (eg, company) [Default Company Ltd]:system:nodes
Organizational Unit Name (eg, section) []:Matrix
Common Name (eg, your name or your server's hostname) []:system:node:ecs-matrix-k8s-cluster-2
Email Address []:root@ecs-matrix-k8s-cluster-2

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Public Cert
# openssl ca -in kubelet.csr -out kubelet.crt -config kubelet.cnf
Using configuration from kubelet.cnf
Enter pass phrase for /etc/pki/CA/private/ca.key:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 3 (0x3)
        Validity
            Not Before: Jun 12 11:39:03 2022 GMT
            Not After : Jun 12 11:39:03 2023 GMT
        Subject:
            countryName               = CN
            stateOrProvinceName       = BJ
            organizationName          = system:nodes
            organizationalUnitName    = Matrix
            commonName                = system:node:ecs-matrix-k8s-cluster-2
            emailAddress              = root@ecs-matrix-k8s-cluster-2
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                71:80:DD:60:EE:49:82:05:68:21:9F:67:DA:5D:52:C0:FA:A1:8F:A1
            X509v3 Authority Key Identifier:
                keyid:EC:90:22:63:D4:73:8D:8E:DC:59:B3:AA:76:18:70:00:A7:37:6D:9D

Certificate is to be certified until Jun 12 11:39:03 2023 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Config

CNI Network

# modprobe br_netfilter

# mkdir /opt/cni/bin -p

# tar xvf cni-plugins-linux-amd64-v0.9.1.tgz -C /opt/cni/bin/
./
./macvlan
./flannel
./static
./vlan
./portmap
./host-local
./vrf
./bridge
./tuning
./firewall
./host-device
./sbr
./loopback
./dhcp
./ptp
./ipvlan
./bandwidth

# mkdir -p /etc/cni/net.d/

# POD_CIDR='10.64.1.0/24'

# cat <<EOF >/etc/cni/net.d/10-bridge.conf
{
    "cniVersion": "0.4.0",
    "name": "bridge",
    "type": "bridge",
    "bridge": "cnio0",
    "isGateway": true,
    "ipMasq": true,
    "ipam": {
        "type": "host-local",
        "ranges": [
          [{"subnet": "${POD_CIDR}"}]
        ],
        "routes": [{"dst": "0.0.0.0/0"}]
    }
}
EOF
         
# cat <<EOF >/etc/cni/net.d/99-loopback.conf
{
    "cniVersion": "0.4.0",
    "name": "lo",
    "type": "loopback"
}
EOF
containerd
# mkdir -p containerd

# tar xvf containerd-1.4.4-linux-amd64.tar.gz -C containerd
bin/
bin/containerd
bin/containerd-shim
bin/containerd-shim-runc-v2
bin/containerd-shim-runc-v1
bin/ctr

# cp -arv containerd/bin/* /bin/
‘containerd/bin/containerd’ -> ‘/bin/containerd’
‘containerd/bin/containerd-shim’ -> ‘/bin/containerd-shim’
‘containerd/bin/containerd-shim-runc-v1’ -> ‘/bin/containerd-shim-runc-v1’
‘containerd/bin/containerd-shim-runc-v2’ -> ‘/bin/containerd-shim-runc-v2’
‘containerd/bin/ctr’ -> ‘/bin/ctr’

# cp runc.amd64 /usr/local/bin/runc

# chmod 755 /usr/local/bin/runc

# mkdir -p /etc/containerd/

# cat <<EOF >/etc/containerd/config.toml
[plugins]
  [plugins.cri.containerd]
    snapshotter = "overlayfs"
    [plugins.cri.containerd.default_runtime]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/bin/runc"
      runtime_root = ""
EOF

# cat <<EOF >/etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
EOF

# systemctl daemon-reload

# systemctl enable --now containerd.service
kubelet
# kubectl config set-cluster ecs-matrix-k8s-cluster-all-in-one --certificate-authority=/etc/etcd/ca.crt --embed-certs=true --server=https://172.16.1.180:6443 --kubeconfig=kubelet.kubeconfig

# kubectl config set-credentials system:node:ecs-matrix-k8s-cluster-2 --client-certificate=/root/certs/kubelet/kubelet.crt --client-key=/root/certs/kubelet/kubelet.key --embed-certs=true --kubeconfig=kubelet.kubeconfig

# kubectl config set-context default --cluster=ecs-matrix-k8s-cluster-all-in-one --user=system:node:ecs-matrix-k8s-cluster-2 --kubeconfig=kubelet.kubeconfig

# kubectl config use-context default --kubeconfig=kubelet.kubeconfig

# mkdir -p /run/systemd/resolve

# ln -s /etc/resolv.conf /run/systemd/resolve/resolv.conf

# cat <<EOF >kubelet-config.yaml
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: "/var/lib/kubernetes/ca.crt"
authorization:
  mode: Webhook
clusterDomain: "cluster.local"
clusterDNS:
  - "10.32.0.10"
podCIDR: "10.64.1.0/24"
resolvConf: "/run/systemd/resolve/resolv.conf"
runtimeRequestTimeout: "15m"
tlsCertFile: "/var/lib/kubelet/kubelet.crt"
tlsPrivateKeyFile: "/var/lib/kubelet/kubelet.key"
EOF

# cp kubelet /usr/local/bin/kubelet

# chmod 755 /usr/local/bin/kubelet

# cat <<EOF >kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service

[Service]
ExecStart=/usr/local/bin/kubelet \
  --config=/var/lib/kubelet/kubelet-config.yaml \
  --container-runtime=remote \
  --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \
  --image-pull-progress-deadline=2m \
  --kubeconfig=/var/lib/kubelet/kubelet.kubeconfig \
  --network-plugin=cni \
  --register-node=true \
  --hostname-override=ecs-matrix-k8s-cluster-2 \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

# systemctl daemon-reload

# systemctl start kubelet.service

Verify

# curl -i http://127.0.0.1:10248/healthz
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Tue, 14 Jun 2022 18:17:06 GMT
Content-Length: 2

ok

# kubectl get nodes
NAME                       STATUS   ROLES    AGE   VERSION
ecs-matrix-k8s-cluster-2   Ready    <none>   19s   v1.21.0

#  curl -s --cacert /etc/etcd/ca.crt  --cert ~/certs/kubelet/kubelet.crt --key ~/certs/kubelet/kubelet.key  https://127.0.0.1:6443/api/v1/nodes | jq '.items[].metadata.name'
"ecs-matrix-k8s-cluster-2"

kube-proxy

Tool download

# yum -y install socat conntrack ipset

# wget https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kube-proxy

Certs

kube-proxy is authenticated with RBAC rule system:node-proxier.

# kubectl get clusterrolebindings system:node-proxier -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-06-11T19:49:53Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:node-proxier
  resourceVersion: "146"
  uid: 0ff8d8c1-5336-4e44-b5c1-3d444884172f
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:node-proxier
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: system:kube-proxy

In kube-proxy cert, O (Organization) should be system:node-proxier which aligned with group name system:node-proxier. And CN (CommanName) should be system:kube-proxy which aligned with subjects user name.

Config
# cat <<EOF > kube-proxy.cnf
[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]

dir             = /etc/pki/CA           # Where everything is kept
certs           = \$dir/certs            # Where the issued certs are kept
crl_dir         = \$dir/crl              # Where the issued crl are kept
database        = \$dir/index.txt        # database index file.

new_certs_dir   = \$dir/newcerts         # default place for new certs.

certificate     = \$dir/ca.crt           # The CA certificate
serial          = \$dir/serial           # The current serial number
crlnumber       = \$dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = \$dir/ca.crl           # The current CRL
private_key     = \$dir/private/ca.key   # The private key
RANDFILE        = \$dir/private/.rand    # private random number file

x509_extensions = usr_cert              # The extentions to add to the cert

name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha256                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering

policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ usr_cert ]
basicConstraints=CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
EOF
Private key
# openssl genrsa -out kube-proxy.key 2048
Cert Request
# openssl req -new -out kube-proxy.csr -key kube-proxy.key
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:Beijing
Organization Name (eg, company) [Default Company Ltd]:system:node-proxier
Organizational Unit Name (eg, section) []:Matrix
Common Name (eg, your name or your server's hostname) []:system:kube-proxy
Email Address []:root@ecs-matrix-k8s-cluster-2

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Public Cert
# openssl ca -in kube-proxy.csr -out kube-proxy.crt -config kube-proxy.cnf

Config

# kubectl config set-cluster ecs-matrix-k8s-cluster-all-in-one --certificate-authority=/etc/etcd/ca.crt --embed-certs=true --server=https://172.16.1.180:6443 --kubeconfig=kube-proxy.kubeconfig

# kubectl config set-credentials system:kube-proxy --client-certificate=/root/certs/kube-proxy/kube-proxy.crt --client-key=/root/certs/kube-proxy/kube-proxy.key --embed-certs=true --kubeconfig=kube-proxy.kubeconfig

# kubectl config set-context default --cluster=ecs-matrix-k8s-cluster-all-in-one --user=system:kube-proxy --kubeconfig=kube-proxy.kubeconfig

# kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

# mkdir /var/lib/kube-proxy

# cp kube-proxy.kubeconfig /var/lib/kube-proxy/kube-proxy.kubeconfig

# cat <<EOF >kube-proxy-config.yaml
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  kubeconfig: "/var/lib/kube-proxy/kube-proxy.kubeconfig"
mode: "iptables"
clusterCIDR: "10.64.1.0/24"
EOF

# cat <<EOF >kube-proxy.service
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-proxy \\
  --config=/var/lib/kube-proxy/kube-proxy-config.yaml \\
  --hostname-override ecs-matrix-k8s-cluster-2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

# cp kube-proxy /usr/local/bin/

# chmod 755 /usr/local/bin/kube-proxy

# systemctl daemon-reload

# systemctl start kube-proxy.service

Verify

# curl -kv http://127.0.0.1:10249/healthz
* About to connect() to 127.0.0.1 port 10249 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 10249 (#0)
> GET /healthz HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:10249
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Tue, 14 Jun 2022 16:47:40 GMT
< Content-Length: 2
<
* Connection #0 to host 127.0.0.1 left intact
ok

# curl http://127.0.0.1:10249/metrics
...snippets...
apiserver_audit_event_total 0
apiserver_audit_requests_rejected_total 0
go_gc_duration_seconds{quantile="0"} 3.3899e-05
go_gc_duration_seconds{quantile="0.25"} 3.8321e-05
go_gc_duration_seconds{quantile="0.5"} 4.9986e-05
go_gc_duration_seconds{quantile="0.75"} 6.9362e-05
go_gc_duration_seconds{quantile="1"} 0.000201038
go_gc_duration_seconds_sum 0.001537893
...snippets...

kube-scheduler

Tool download

# wget https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kube-scheduler

Certs

same auth as kube-proxy

# kubectl get clusterrolebindings system:kube-scheduler -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-04-23T20:12:28Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-scheduler
  resourceVersion: "149"
  uid: b0e03403-9787-4829-bac7-96cfe4c9c0f9
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-scheduler
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: system:kube-scheduler
config
# cat <<EOF >scheduler.cnf
[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]

dir             = /etc/pki/CA           # Where everything is kept
certs           = \$dir/certs            # Where the issued certs are kept
crl_dir         = \$dir/crl              # Where the issued crl are kept
database        = \$dir/index.txt        # database index file.

new_certs_dir   = \$dir/newcerts         # default place for new certs.

certificate     = \$dir/ca.crt           # The CA certificate
serial          = \$dir/serial           # The current serial number
crlnumber       = \$dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = \$dir/ca.crl           # The current CRL
private_key     = \$dir/private/ca.key   # The private key
RANDFILE        = \$dir/private/.rand    # private random number file

x509_extensions = usr_cert              # The extentions to add to the cert

name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha256                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering

policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ usr_cert ]

basicConstraints=CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
EOF
Private key
# openssl genrsa -out scheduler.key 2048
Cert Request
# openssl req -new -out scheduler.csr -key scheduler.key
Generating RSA private key, 2048 bit long modulus
..+++
...........................................+++
e is 65537 (0x10001)
[root@ecs-matrix-k8s-cluster-2 scheduler]# openssl req -new -out scheduler.csr -key scheduler.key
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:Beijing
Organization Name (eg, company) [Default Company Ltd]:system:kube-scheduler
Organizational Unit Name (eg, section) []:ecs-matrix-k8s-cluster-2
Common Name (eg, your name or your server's hostname) []:system:kube-scheduler
Email Address []:root@ecs-matrix-k8s-cluster-2

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Public Cert
# openssl ca -in scheduler.csr -out scheduler.crt -config scheduler.cnf

Config

# kubectl config set-cluster ecs-matrix-k8s-cluster-all-in-one --certificate-authority=/etc/etcd/ca.crt --embed-certs=true --server=https://127.0.0.1:6443 --kubeconfig=kube-scheduler.kubeconfig

# kubectl config set-credentials system:kube-scheduler --client-certificate=/root/certs/scheduler/scheduler.crt --client-key=/root/certs/scheduler/scheduler.key --embed-certs=true --kubeconfig=kube-scheduler.kubeconfig

# kubectl config set-context default --cluster=ecs-matrix-k8s-cluster-all-in-one --user=system:kube-scheduler --kubeconfig=kube-scheduler.kubeconfig

# kubectl config use-context default --kubeconfig=kube-scheduler.kubeconfig

# cp kube-scheduler.kubeconfig /var/lib/kubernetes/kube-scheduler.kubeconfig

# cat <<EOF > kube-scheduler.yaml
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
  leaderElect: true
EOF

# mkdir -p /etc/kubernetes/config/

# cp kube-scheduler.yaml /etc/kubernetes/config/

# cp kube-scheduler /usr/local/bin/

# chmod 755 /usr/local/bin/kube-scheduler

# cat <<EOF > kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler --config=/etc/kubernetes/config/kube-scheduler.yaml --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Verify

#  curl -v http://127.0.0.1:10251/healthz
* About to connect() to 127.0.0.1 port 10251 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 10251 (#0)
> GET /healthz HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:10251
> Accept: */*
>
< HTTP/1.1 200 OK
< Cache-Control: no-cache, private
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Sun, 12 Jun 2022 19:06:56 GMT
< Content-Length: 2
<
* Connection #0 to host 127.0.0.1 left intact
ok

# kubectl get cs scheduler
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME        STATUS    MESSAGE   ERROR
scheduler   Healthy   ok

kube-controller-manager

Tool download

# wget https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kube-controller-manager

Cert

same auth as kube-proxy

# kubectl get clusterrolebindings system:kube-controller-manager -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-06-11T19:49:53Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-controller-manager
  resourceVersion: "147"
  uid: 808c97e8-279d-4716-a0e7-d00c84becd26
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-controller-manager
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: system:kube-controller-manager
config
# cat <<EOF >controller-manager.cnf
[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]

dir             = /etc/pki/CA           # Where everything is kept
certs           = \$dir/certs            # Where the issued certs are kept
crl_dir         = \$dir/crl              # Where the issued crl are kept
database        = \$dir/index.txt        # database index file.

new_certs_dir   = \$dir/newcerts         # default place for new certs.

certificate     = \$dir/ca.crt           # The CA certificate
serial          = \$dir/serial           # The current serial number
crlnumber       = \$dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = \$dir/ca.crl           # The current CRL
private_key     = \$dir/private/ca.key   # The private key
RANDFILE        = \$dir/private/.rand    # private random number file

x509_extensions = usr_cert              # The extentions to add to the cert

name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha256                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering

policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ usr_cert ]
basicConstraints=CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
EOF
Private key
# openssl genrsa -out controller-manager.key 2048
Cert Request
# openssl req -new -out controller-manager.csr -key controller-manager.key
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:Beijing
Organization Name (eg, company) [Default Company Ltd]:system:kube-controller-manager
Organizational Unit Name (eg, section) []:Matrix
Common Name (eg, your name or your server's hostname) []:system:kube-controller-manager
Email Address []:root@ecs-matrix-k8s-cluster-2

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Public Cert
# openssl ca -in controller-manager.csr -out controller-manager.crt -config controller-manager.cnf

Config

# cp controller-manager.crt /var/lib/kubernetes/controller-manager.crt

# sed -E -i '/service-account-key-file/s/apiserver.crt/controller-manager.crt/' /etc/systemd/system/kube-apiserver.service

# sed -E -i '/service-account-signing-key-file/s/apiserver.key/controller-manager.key/' /etc/systemd/system/kube-apiserver.service

# systemctl daemon-reload

# systemctl restart kube-apiserver.service

# kubectl config set-cluster ecs-matrix-k8s-cluster-all-in-one  --certificate-authority=/etc/etcd/ca.crt --embed-certs=true --server=https://127.0.0.1:6443 --kubeconfig=controller-manager.kubeconfig

# kubectl config set-credentials system:kube-controller-manager --client-certificate=/root/certs/controller-manager/controller-manager.crt --client-key=/root/certs/controller-manager/controller-manager.key --embed-certs=true --kubeconfig=controller-manager.kubeconfig

# kubectl config set-context default --cluster=ecs-matrix-k8s-cluster-all-in-one --user=system:kube-controller-manager --kubeconfig=controller-manager.kubeconfig

# kubectl config use-context default --kubeconfig=controller-manager.kubeconfig

# openssl rsa -in /etc/pki/CA/private/ca.key  > ca.key

# cp ca.key /var/lib/kubernetes/ca.key

# cp controller-manager.key /var/lib/kubernetes/controller-manager.key

# cp controller-manager.kubeconfig /var/lib/kubernetes/kube-controller-manager.kubeconfig

# cp kube-controller-manager /usr/local/bin/kube-controller-manager

# chmod 755 /usr/local/bin/kube-controller-manager

# cat <<EOF > /etc/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \
  --bind-address=0.0.0.0 \
  --cluster-cidr=10.64.0.0/16 \
  --cluster-name=kubernetes \
  --cluster-signing-cert-file=/var/lib/kubernetes/ca.crt \
  --cluster-signing-key-file=/var/lib/kubernetes/ca.key \
  --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \
  --leader-elect=true \
  --root-ca-file=/var/lib/kubernetes/ca.crt \
  --service-account-private-key-file=/var/lib/kubernetes/controller-manager.key \
  --service-cluster-ip-range=10.32.0.0/24 \
  --use-service-account-credentials=true \
  --v=2
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

# systemctl daemon-reload

# systemctl start kube-controller-manager.service

Verify

# kubectl get cs controller-manager
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE   ERROR
controller-manager   Healthy   ok

# curl -i http://127.0.0.1:10252/healthz
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Tue, 14 Jun 2022 17:44:44 GMT
Content-Length: 2

ok

coredns add-on

Deploy

# cat <<EOF > coredns-1.8.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: coredns
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:coredns
rules:
- apiGroups:
  - ""
  resources:
  - endpoints
  - services
  - pods
  - namespaces
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:coredns
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:coredns
subjects:
- kind: ServiceAccount
  name: coredns
  namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        template ANY HINFO . {
            rcode NXDOMAIN
        }
        log
        errors
        health
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/name: "CoreDNS"
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels:
      k8s-app: kube-dns
  template:
    metadata:
      labels:
        k8s-app: kube-dns
    spec:
      priorityClassName: system-cluster-critical
      serviceAccountName: coredns
      tolerations:
        - key: "CriticalAddonsOnly"
          operator: "Exists"
      nodeSelector:
        beta.kubernetes.io/os: linux
      containers:
      - name: coredns
        image: coredns/coredns:1.8.3
        imagePullPolicy: IfNotPresent
        resources:
          limits:
            memory: 170Mi
          requests:
            cpu: 100m
            memory: 70Mi
        args: [ "-conf", "/etc/coredns/Corefile" ]
        volumeMounts:
        - name: config-volume
          mountPath: /etc/coredns
          readOnly: true
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
        - containerPort: 9153
          name: metrics
          protocol: TCP
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - all
          readOnlyRootFilesystem: true
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: 8181
            scheme: HTTP
      dnsPolicy: Default
      volumes:
        - name: config-volume
          configMap:
            name: coredns
            items:
            - key: Corefile
              path: Corefile
---
apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  annotations:
    prometheus.io/port: "9153"
    prometheus.io/scrape: "true"
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: "CoreDNS"
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 10.32.0.10
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP
  - name: metrics
    port: 9153
    protocol: TCP
EOF

# kubectl apply -f coredns-1.8.yaml

Verify

# kubectl run busybox --image=busybox:1.28 --command -- sleep 3600

# kubectl exec -ti busybox -- nslookup kubernetes
Server:    10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local

# kubectl exec -ti busybox -- nslookup www.google.com
Server:    10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local

Name:      www.google.com
Address 1: 2a00:1450:4019:801::2004 fjr02s09-in-x04.1e100.net
Address 2: 172.217.19.164 zrh04s07-in-f4.1e100.net

# kubectl get pods -n kube-system -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP          NODE                       NOMINATED NODE   READINESS GATES
coredns-8494f9c688-j2dbg   1/1     Running   0          24h   10.64.1.7   ecs-matrix-k8s-cluster-2   <none>           <none>

# ping -c1 -w1 10.64.1.7
PING 10.64.1.7 (10.64.1.7): 56 data bytes
64 bytes from 10.64.1.7: seq=0 ttl=64 time=0.068 ms

--- 10.64.1.7 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.068/0.068/0.068 ms

Test

# kubectl create deployment nginx --image=nginx

# kubectl get pods -l app=nginx
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6799fc88d8-stvrl   1/1     Running   0          79s

# kubectl port-forward nginx-6799fc88d8-stvrl 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

# curl --head http://127.0.0.1:8080
HTTP/1.1 200 OK
Server: nginx/1.21.6
Date: Wed, 15 Jun 2022 19:29:18 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
Connection: keep-alive
ETag: "61f01158-267"
Accept-Ranges: bytes

# kubectl logs nginx-6799fc88d8-stvrl
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/06/15 19:26:34 [notice] 1#1: using the "epoll" event method
2022/06/15 19:26:34 [notice] 1#1: nginx/1.21.6
2022/06/15 19:26:34 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2022/06/15 19:26:34 [notice] 1#1: OS: Linux 3.10.0-957.27.2.el7.x86_64
2022/06/15 19:26:34 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2022/06/15 19:26:34 [notice] 1#1: start worker processes
2022/06/15 19:26:34 [notice] 1#1: start worker process 30
2022/06/15 19:26:34 [notice] 1#1: start worker process 31
127.0.0.1 - - [15/Jun/2022:19:28:58 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
127.0.0.1 - - [15/Jun/2022:19:29:18 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.29.0" "-"

# kubectl exec -ti nginx-6799fc88d8-stvrl -- nginx -v
nginx version: nginx/1.21.6

# kubectl expose deployment nginx --port 80 --type NodePort
service/nginx exposed

# kubectl get svc nginx -o jsonpath='{range .spec.ports[0]}{.nodePort}'
31824

# curl -I http://localhost:31824
HTTP/1.1 200 OK
Server: nginx/1.21.6
Date: Wed, 15 Jun 2022 19:32:31 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
Connection: keep-alive
ETag: "61f01158-267"
Accept-Ranges: bytes

# kubectl exec -ti  busybox -- nslookup nginx
Server:    10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx
Address 1: 10.32.0.223 nginx.default.svc.cluster.local

# kubectl delete deployment nginx
deployment.apps "nginx" deleted

# kubectl delete svc nginx
service "nginx" deleted
Tags: