跳转到内容

单Master节点部署Kubernetes ​

环境信息 ​

  • 🐧 操作系统:Ubuntu 22.04.3 LTS
  • ☸️ Kubernetes:v1.35.4
  • 📦 容器运行时:containerd 2.2.3
  • 🌐 网络插件:Calico v3.25.0
  • 🔍 DNS:CoreDNS 1.11.3
  • 🔐 证书工具:cfssl 1.6.5
  • 🗄️ KV存储:etcd v3.6.10
  • 🌐 IP 地址:192.168.60.128(Master)

安装执行 ​

注意:执行前请将脚本中的 IP 地址修改为实际 Master 节点 IP

bash
# 1.下载
curl -OL "https://cnb.cool/zhucuiding/docs/-/releases/download/k8s/k8s-1.35.4.tar.gz"
# 2.解压
tar -zxvf k8s-1.35.4.tar.gz && cd k8s-1.35.4
# 3.初始化环境
bash init-k8s.sh
# 4.安装containerd
cd containerd && bash install.sh
# 5. 安装cfssl
cd cfssl && bash install.sh
# 6.安装etcd
cd etcd && bash install.sh
# 7.安装k8s
cd k8s && bash install.sh
# 8.安装calico
kubectl apply -f calico.yaml
# 9.安装coredns
cd coredns && bash install.sh

说明:

  • 初始化执行包含关闭swap,关闭防火墙和修改内核参数
  • 使用containerd,脚本内已包含crictl命令
  • 安装cfssl是为后续的etcd和k8s相关组件生成证书

脚本详情 ​

脚本文件位于 scripts/ 目录下,可直接下载使用

环境初始化 ​

scripts/init-k8s.sh

bash
#! /bin/bash

function get_ip() {
    ip=$(hostname -I | awk '{print $1}')
}

function set_hostname() {
    hostnamectl set-hostname master
}

function set_swap() {
    swapoff -a
    sed -i '/^[^#]*swap/ s/^/#/' /etc/fstab
}

function set_ufw() {
    systemctl disable --now ufw
}

function set_hosts() {
    HOSTS_ENTRY="$ip master"
    if grep -q "^$HOSTS_ENTRY" /etc/hosts; then
        echo "Hosts entry already exists, skipping..."
    else
        echo "$HOSTS_ENTRY" | sudo tee -a /etc/hosts
        echo "Hosts entry added successfully"
    fi
}

function configure_kernel_params() {
    cat >/etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF
    modprobe overlay && modprobe br_netfilter

    cat >/etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
    sysctl --system >/dev/null 2>&1
    sysctl net.bridge.bridge-nf-call-iptables
    sysctl net.ipv4.ip_forward
}

function main() {
    get_ip
    set_hostname
    set_swap
    set_ufw
    set_hosts
    configure_kernel_params
}

main "$@"

Containerd ​

scripts/containerd/install.sh

bash
#! /bin/bash
#
# curl -LO https://github.com/containerd/containerd/releases/download/v2.2.3/containerd-2.2.3-linux-amd64.tar.gz
# curl -LO https://github.com/opencontainers/runc/releases/download/v1.4.2/runc.amd64
# curl -LO https://github.com/containernetworking/plugins/releases/download/v1.9.1/cni-plugins-linux-amd64-v1.9.1.tgz
# curl -LO https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.35.0/crictl-v1.35.0-linux-amd64.tar.gz

containerd_file=containerd-2.2.3-linux-amd64.tar.gz
runc_file=runc.amd64
cni_file=cni-plugins-linux-amd64-v1.9.1.tgz
crictl_file=crictl-v1.35.0-linux-amd64.tar.gz

function cni_install() {
    mkdir -p /opt/cni/bin
    tar Cxzvf /opt/cni/bin $cni_file
}

function containerd_install() {
    if command -v containerd &>/dev/null; then
        "containerd已存在,安装失败"
        exit 1
    fi
    echo "开始安装containerd"

    tar -zxvf $containerd_file
    cp bin/* /usr/local/bin/
    rm -rf bin
    install -m 755 $runc_file /usr/local/sbin/runc

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

[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd

Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target
EOF
    # 配置 containerd(此处放containerd.toml文件会覆盖config.toml中的内容)
    mkdir -p /etc/containerd/conf.d
    /usr/local/bin/containerd config default >/etc/containerd/config.toml
    cat >/etc/containerd/conf.d/containerd.toml <<EOF
[plugins.'io.containerd.cri.v1.images'.registry]
  config_path = ''
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
  SystemdCgroup = true
EOF
    # 配置代理拉取镜像
    mkdir -p /etc/systemd/system/containerd.service.d
    cat >/etc/systemd/system/containerd.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://192.168.60.1:12450"
Environment="HTTPS_PROXY=http://192.168.60.1:12450"
Environment="NO_PROXY=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.svc,.cluster.local,.ewhisper.cn"
EOF
    # 启动服务
    systemctl daemon-reload
    systemctl enable --now containerd

    if systemctl is-active --quiet containerd; then
        echo "containerd 安装成功"
        return 0
    else
        echo "containerd 启动失败"
        journalctl -u containerd -n 10
        return 1
    fi
}

function crictl_install() {
    tar Czxvf /usr/local/bin $crictl_file
    # 消除警告在使用crictl时
    cat >/etc/crictl.yaml <<EOF
runtime-endpoint: "unix:///var/run/containerd/containerd.sock"
image-endpoint: "unix:///var/run/containerd/containerd.sock"
timeout: 30
debug: false
EOF
}

function main() {
    cni_install
    containerd_install
    crictl_install
}

main "$@"

scripts/containerd/uninstall.sh

bash
#! /bin/bash

function containerd_uninstall() {
    if ! command -v containerd &>/dev/null; then
        echo "containerd 未安装"
        return 0
    fi

    echo "开始卸载 containerd..."
    # 停止服务
    systemctl stop containerd 2>/dev/null || true
    systemctl disable containerd 2>/dev/null || true

    # 删除文件
    rm -f /etc/systemd/system/containerd.service
    rm -f /usr/local/bin/containerd*
    rm -f /usr/local/bin/ctr
    rm -rf /etc/systemd/system/containerd.service.d
    rm -rf /etc/containerd
    rm -rf /etc/crictl.yaml
    rm -rf /var/lib/containerd
    rm -rf /run/containerd

    rm -rf /usr/local/sbin/runc
    rm -rf /usr/local/bin/crictl

    # 删除自动生成的目录
    rm -rf /run/containerd
    rm -rf /var/log/containerd

    # 重新加载
    systemctl daemon-reload

    echo "containerd 卸载完成"
    return 0
}
function cni_uninstall() {
    rm -rf /opt/cni
    rm -rf /etc/cni
    rm -rf /var/lib/cni
}

function main() {
    containerd_uninstall
    cni_uninstall
}

main "$@"

CFSSL ​

scripts/cfssl/install.sh

bash
#! /bin/bash

# curl -x http://192.168.60.1:12450 -LO https://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssl_1.6.5_linux_amd64
# curl -x http://192.168.60.1:12450 -LO https://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssljson_1.6.5_linux_amd64

cfssl_file=cfssl_1.6.5_linux_amd64
cfssljson_file=cfssljson_1.6.5_linux_amd64

function cfssl_install() {
    echo "开始安装cfssl"
    install -m 755 $cfssl_file /usr/local/bin/cfssl
    install -m 755 $cfssljson_file /usr/local/bin/cfssljson
    echo "cfssl安装完成"
}

function main() {
    cfssl_install
}

main "$@"

scripts/cfssl/uninstall.sh

bash
#! /bin/bash

function cfssl_uninstall() {
    echo "开始卸载cfssl"
    rm -rf /usr/local/bin/cfssl
    rm -rf /usr/local/bin/cfssljson
    echo "卸载cfssl完成"
}

function main() {
    cfssl_uninstall
}

main "$@"

ETCD ​

scripts/etcd/install.sh

bash
#! /bin/bash

# curl -x http://192.168.60.1:12450 -LO https://github.com/etcd-io/etcd/releases/download/v3.6.10/etcd-v3.6.10-linux-amd64.tar.gz

#root@master:~/master/etcd# etcdctl \
#  --endpoints=https://192.168.60.128:2379 \
#  --cacert=/etc/etcd/ssl/etcd-ca.pem \
#  --cert=/etc/etcd/ssl/client.pem \
#  --key=/etc/etcd/ssl/client-key.pem \
#  endpoint health

# etcd-ca.pem CA 根证书(所有节点共用)
# server.pem / server-key.pem 服务端证书(etcd 对外服务)
# client.pem / client-key.pem 客户端证书(kube-apiserver 访问 etcd)
# peer-master.pem / peer-master-key.pem Peer 证书(etcd 节点间通信)

etcd_file=etcd-v3.6.10-linux-amd64
etcd_ip="192.168.60.128"
etcd_host="master"
cert_dir="/etc/etcd/ssl"

function etcd_install() {
  echo "开始安装etcd"
  tar -zxvf $etcd_file.tar.gz
  cp -a $etcd_file/etcd* /usr/local/bin
  rm -rf $etcd_file
}

function etcd_ca_gencert() {
  mkdir -p $cert_dir
  cd $cert_dir
  # 创建 CA 配置文件
  cat >ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "43800h"
    },
    "profiles": {
      "server": {
        "expiry": "43800h",
        "usages": ["signing", "key encipherment", "server auth"]
      },
      "client": {
        "expiry": "43800h",
        "usages": ["signing", "key encipherment", "client auth"]
      },
      "peer": {
        "expiry": "43800h",
        "usages": ["signing", "key encipherment", "server auth", "client auth"]
      }
    }
  }
}
EOF
  echo "创建CA配置文件完成"
  # 创建 CA 证书签名请求
  cat >ca-csr.json <<EOF
{
  "CN": "etcd-ca",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "Beijing",
      "L": "Beijing",
      "O": "etcd",
      "OU": "CA"
    }
  ]
}
EOF
  # 生成 CA 根证书
  cfssl gencert -initca ca-csr.json | cfssljson -bare ca
  mv ca.pem etcd-ca.pem
  mv ca-key.pem etcd-ca-key.pem
  echo "生成CA根证书完成"

  # 创建服务端证书请求
  cat >server-csr.json <<EOF
{
  "CN": "etcd-server",
  "hosts": ["127.0.0.1", "localhost", "$etcd_ip", "$etcd_host", "::1"],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "Beijing",
      "L": "Beijing",
      "O": "etcd",
      "OU": "Server"
    }
  ]
}
EOF
  echo "创建服务端证书请求完成"
  # 生成服务端证书
  cfssl gencert \
    -ca=etcd-ca.pem \
    -ca-key=etcd-ca-key.pem \
    -config=ca-config.json \
    -profile=server \
    server-csr.json | cfssljson -bare server
  echo "生成服务端证书完成"

  # 创建客户端证书请求
  cat >client-csr.json <<EOF
{
  "CN": "etcd-client",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "Beijing",
      "L": "Beijing",
      "O": "etcd",
      "OU": "Client"
    }
  ]
}
EOF
  echo "创建客户端证书请求完成"
  # 生成客户端证书
  cfssl gencert \
    -ca=etcd-ca.pem \
    -ca-key=etcd-ca-key.pem \
    -config=ca-config.json \
    -profile=client \
    client-csr.json | cfssljson -bare client
  echo "客户端证书生成完成"

  # 生成 Peer 证书
  cat >peer-csr.json <<EOF
{
  "CN": "etcd-peer-${etcd_host}",
  "hosts": ["127.0.0.1", "localhost", "$etcd_ip", "$etcd_host", "::1"],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "Beijing",
      "L": "Beijing",
      "O": "etcd",
      "OU": "Peer"
    }
  ]
}
EOF
  echo "生成 Peer 证书完成"
  # 生成 Peer 证书
  cfssl gencert \
    -ca=etcd-ca.pem \
    -ca-key=etcd-ca-key.pem \
    -config=ca-config.json \
    -profile=peer \
    peer-csr.json | cfssljson -bare "peer-${etcd_host}"
  echo "peer证书生成完成"
}

function etct_service_config() {
  echo "创建etcd服务配置"
  cat >/etc/systemd/system/etcd.service <<EOF
[Unit]
Description=etcd key-value store
Documentation=https://github.com/etcd-io/etcd
After=network.target

[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \\
  --name=${etcd_host} \\
  --data-dir=/var/lib/etcd \\
  --listen-client-urls=https://${etcd_ip}:2379,https://127.0.0.1:2379 \\
  --advertise-client-urls=https://${etcd_ip}:2379 \\
  --listen-peer-urls=https://${etcd_ip}:2380 \\
  --initial-advertise-peer-urls=https://${etcd_ip}:2380 \\
  --initial-cluster=${etcd_host}=https://${etcd_ip}:2380 \\
  --initial-cluster-state=new \\
  --initial-cluster-token=etcd-cluster-0 \\
  --client-cert-auth \\
  --trusted-ca-file=/etc/etcd/ssl/etcd-ca.pem \\
  --cert-file=/etc/etcd/ssl/server.pem \\
  --key-file=/etc/etcd/ssl/server-key.pem \\
  --peer-client-cert-auth \\
  --peer-trusted-ca-file=/etc/etcd/ssl/etcd-ca.pem \\
  --peer-cert-file=/etc/etcd/ssl/peer-${etcd_host}.pem \\
  --peer-key-file=/etc/etcd/ssl/peer-${etcd_host}-key.pem
Restart=always
RestartSec=10
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

  systemctl daemon-reload && systemctl enable --now etcd
  echo "etcd 服务配置完成"
}

function main() {
  etcd_install
  etcd_ca_gencert
  etct_service_config
}

main "$@"

scripts/etcd/uninstall.sh

bash
#! /bin/bash

function etcd_uninstall() {
    echo "开始卸载etcd"

    echo "关闭etcd服务"
    systemctl disable --now etcd

    echo "删除etcd存储目录"
    rm -rf /var/lib/etcd

    echo "删除证书目录"
    rm -rf /etc/etcd/ssl

    echo "删除etcd二进制文件"
    rm -rf /usr/local/bin/etcd*

    echo "卸载etcd完成"
}

function main() {
    etcd_uninstall
}

main "$@"

Kubernetes ​

scripts/k8s/k8s-download.sh

bash
#! /bin/bash

k8s_version=v1.35.4
base_url=https://dl.k8s.io/$k8s_version/bin/linux/amd64
mkdir -p k8s-binaries

components=(
    kube-apiserver
    kube-controller-manager
    kube-proxy
    kube-scheduler
    kubectl
    kubelet
)

function k8s_download() {
    for component in "${components[@]}"; do
        url="$base_url/$component"
        echo "开始下载: $component"
        curl -x http://192.168.60.1:12450 \
            --tlsv1.2 \
            --connect-timeout 30 \
            --retry 5 \
            --retry-delay 2 \
            -LO "$url"
        mv $component k8s-binaries/
    done
}

function main() {
    k8s_download
}

main "$@"

scripts/k8s/install.sh

bash
#! /bin/bash

# kubernetes-ca.pem   Kubernetes CA 根证书
# apiserver.pem   API Server 服务端证书
# apiserver-kubelet-client.pem    API Server 访问 kubelet
# scheduler.pem   调度器客户端证书
# controller-manager.pem  控制器管理器客户端证书
# admin.pem   管理员 kubectl 证书
# kube-proxy.pem  kube-proxy 客户端证书

master_ip="192.168.60.128"
master_host="master"

function install_k8s_binaries() {
    install -m 755 k8s-binaries/kube* /usr/local/bin/
}

function gencert_k8s_certs() {

    mkdir -p /etc/kubernetes/pki
    cd /etc/kubernetes/pki

    # 创建ca配置文件
    cat >ca-config.json <<'EOF'
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
        "expiry": "87600h",
        "usages": ["signing", "key encipherment", "server auth", "client auth"]
      }
    }
  }
}
EOF
    echo "ca配置文件创建完成"

    cat >ca-csr.json <<'EOF'
{
  "CN": "kubernetes-ca",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "Beijing",
      "L": "Beijing",
      "O": "Kubernetes",
      "OU": "CA"
    }
  ]
}
EOF
    echo "ca证书请求文件创建完成"

    cfssl gencert -initca ca-csr.json | cfssljson -bare kubernetes-ca
    echo "ca根证书生成完成"

    cat >apiserver-csr.json <<EOF
{
  "CN": "kube-apiserver",
  "hosts": [
    "127.0.0.1",
    "localhost",
    "${master_ip}",
    "10.96.0.1",
    "${master_host}",
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster.local"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "Beijing",
      "L": "Beijing",
      "O": "Kubernetes",
      "OU": "apiserver"
    }
  ]
}
EOF
    cfssl gencert \
        -ca=kubernetes-ca.pem \
        -ca-key=kubernetes-ca-key.pem \
        -config=ca-config.json \
        -profile=kubernetes \
        apiserver-csr.json | cfssljson -bare apiserver
    echo "apiserver证书生成完成"

    cat >apiserver-kubelet-client-csr.json <<'EOF'
{
  "CN": "kube-apiserver-kubelet-client",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "Beijing",
      "L": "Beijing",
      "O": "system:masters",
      "OU": "Kubernetes"
    }
  ]
}
EOF

    cfssl gencert \
        -ca=kubernetes-ca.pem \
        -ca-key=kubernetes-ca-key.pem \
        -config=ca-config.json \
        -profile=kubernetes \
        apiserver-kubelet-client-csr.json | cfssljson -bare apiserver-kubelet-client
    echo "apiserver-kubelet-client 证书生成完成"

    cat >scheduler-csr.json <<'EOF'
{
  "CN": "system:kube-scheduler",
  "key": { "algo": "rsa", "size": 2048 },
  "names": [{ "O": "system:kube-scheduler", "OU": "Kubernetes" }]
}
EOF

    cfssl gencert \
        -ca=kubernetes-ca.pem \
        -ca-key=kubernetes-ca-key.pem \
        -config=ca-config.json \
        -profile=kubernetes \
        scheduler-csr.json | cfssljson -bare scheduler
    echo "scheduler 证书生成完成"

    cat >controller-manager-csr.json <<'EOF'
{
  "CN": "system:kube-controller-manager",
  "key": { "algo": "rsa", "size": 2048 },
  "names": [{ "O": "system:kube-controller-manager", "OU": "Kubernetes" }]
}
EOF

    cfssl gencert \
        -ca=kubernetes-ca.pem \
        -ca-key=kubernetes-ca-key.pem \
        -config=ca-config.json \
        -profile=kubernetes \
        controller-manager-csr.json | cfssljson -bare controller-manager
    echo "controller-manager 证书生成完成"

    cat >kubelet-csr.json <<EOF
{
  "CN": "system:node:master",
  "hosts": ["127.0.0.1", "localhost", "${master_ip}", "${master_host}"],
  "key": { "algo": "rsa", "size": 2048 },
  "names": [{ "O": "system:nodes", "OU": "Kubernetes" }]
}
EOF
    cfssl gencert \
        -ca=kubernetes-ca.pem \
        -ca-key=kubernetes-ca-key.pem \
        -config=ca-config.json \
        -profile=kubernetes \
        kubelet-csr.json | cfssljson -bare kubelet
    echo "kubelet 证书生成完成"

    cat >admin-csr.json <<'EOF'
{
  "CN": "admin",
  "key": { "algo": "rsa", "size": 2048 },
  "names": [{ "O": "system:masters", "OU": "Kubernetes" }]
}
EOF

    cfssl gencert \
        -ca=kubernetes-ca.pem \
        -ca-key=kubernetes-ca-key.pem \
        -config=ca-config.json \
        -profile=kubernetes \
        admin-csr.json | cfssljson -bare admin
    echo "admin 证书生成完成"

    cat >kube-proxy-csr.json <<'EOF'
{
  "CN": "system:kube-proxy",
  "key": { "algo": "rsa", "size": 2048 },
  "names": [{ "O": "system:node-proxier", "OU": "Kubernetes" }]
}
EOF

    cfssl gencert \
        -ca=kubernetes-ca.pem \
        -ca-key=kubernetes-ca-key.pem \
        -config=ca-config.json \
        -profile=kubernetes \
        kube-proxy-csr.json | cfssljson -bare kube-proxy
    echo "kube-proxy 证书生成完成"

    chmod 600 *-key.pem
    chmod 644 *.pem
    echo "所有证书生成完成"
}

function start_apiserver() {
    cat >/etc/systemd/system/kube-apiserver.service <<EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://kubernetes.io/docs/home/
After=network.target
After=etcd.service

[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
  --advertise-address=${master_ip} \\
  --allow-privileged=true \\
  --authorization-mode=Node,RBAC \\
  --client-ca-file=/etc/kubernetes/pki/kubernetes-ca.pem \\
  --enable-admission-plugins=NodeRestriction \\
  --enable-bootstrap-token-auth=true \\
  --etcd-cafile=/etc/etcd/ssl/etcd-ca.pem \\
  --etcd-certfile=/etc/etcd/ssl/client.pem \\
  --etcd-keyfile=/etc/etcd/ssl/client-key.pem \\
  --etcd-servers=https://${master_ip}:2379 \\
  --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.pem \\
  --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client-key.pem \\
  --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \\
  --secure-port=6443 \\
  --service-account-issuer=https://kubernetes.default.svc.cluster.local \\
  --service-account-key-file=/etc/kubernetes/pki/apiserver-key.pem \\
  --service-account-signing-key-file=/etc/kubernetes/pki/apiserver-key.pem \\
  --service-cluster-ip-range=10.96.0.0/12 \\
  --tls-cert-file=/etc/kubernetes/pki/apiserver.pem \\
  --tls-private-key-file=/etc/kubernetes/pki/apiserver-key.pem \\
  --v=2
Restart=always
RestartSec=10
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable --now kube-apiserver
}

function start_scheduler() {
    cat >/etc/systemd/system/kube-scheduler.service <<'EOF'
[Unit]
Description=Kubernetes Scheduler
Documentation=https://kubernetes.io/docs/home/
After=network.target
After=kube-apiserver.service

[Service]
ExecStart=/usr/local/bin/kube-scheduler \
  --leader-elect=true \
  --kubeconfig=/etc/kubernetes/scheduler.conf \
  --v=2
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

    cat >/etc/kubernetes/scheduler.conf <<EOF
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/kubernetes-ca.pem
    server: https://$master_ip:6443
  name: kubernetes
users:
- name: system:kube-scheduler
  user:
    client-certificate: /etc/kubernetes/pki/scheduler.pem
    client-key: /etc/kubernetes/pki/scheduler-key.pem
contexts:
- context:
    cluster: kubernetes
    user: system:kube-scheduler
  name: system:kube-scheduler
current-context: system:kube-scheduler
EOF
    systemctl daemon-reload
    systemctl enable --now kube-scheduler
}

function start_controller_manager() {
    cat >/etc/systemd/system/kube-controller-manager.service <<'EOF'
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
After=network.target

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \
      --v=2 \
      --bind-address=0.0.0.0 \
      --root-ca-file=/etc/kubernetes/pki/kubernetes-ca.pem \
      --cluster-signing-cert-file=/etc/kubernetes/pki/kubernetes-ca.pem \
      --cluster-signing-key-file=/etc/kubernetes/pki/kubernetes-ca-key.pem \
      --service-account-private-key-file=/etc/kubernetes/pki/apiserver-key.pem \
      --kubeconfig=/etc/kubernetes/controller-manager.conf \
      --leader-elect=true \
      --use-service-account-credentials=true \
      --node-monitor-grace-period=40s \
      --node-monitor-period=5s \
      --controllers=*,bootstrapsigner,tokencleaner \
      --allocate-node-cidrs=true \
      --service-cluster-ip-range=10.96.0.0/12 \
      --cluster-cidr=10.244.0.0/16 \
      --node-cidr-mask-size-ipv4=24

Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target
EOF

    cat >/etc/kubernetes/controller-manager.conf <<EOF
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/kubernetes-ca.pem
    server: https://$master_ip:6443
  name: kubernetes
users:
- name: system:kube-controller-manager
  user:
    client-certificate: /etc/kubernetes/pki/controller-manager.pem
    client-key: /etc/kubernetes/pki/controller-manager-key.pem
contexts:
- context:
    cluster: kubernetes
    user: system:kube-controller-manager
  name: system:kube-controller-manager
current-context: system:kube-controller-manager
EOF
    systemctl daemon-reload
    systemctl enable --now kube-controller-manager
}

function start_kubelet() {
    mkdir -p /var/lib/kubelet
    cat >/var/lib/kubelet/config.yaml <<'EOF'
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
containerRuntimeEndpoint: unix:///var/run/containerd/containerd.sock
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
    cacheTTL: 2m
  x509:
    clientCAFile: /etc/kubernetes/pki/kubernetes-ca.pem
authorization:
  mode: Webhook
  webhook:
    cacheAuthorizedTTL: 5m
    cacheUnauthorizedTTL: 30s
EOF
    cat >/etc/kubernetes/kubelet.conf <<EOF
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/kubernetes-ca.pem
    server: https://$master_ip:6443
  name: kubernetes
users:
- name: system:node:master
  user:
    client-certificate: /etc/kubernetes/pki/kubelet.pem
    client-key: /etc/kubernetes/pki/kubelet-key.pem
contexts:
- context:
    cluster: kubernetes
    user: system:node:master
  name: default
current-context: default
EOF
    cat >/etc/systemd/system/kubelet.service <<'EOF'
[Unit]
Description=Kubernetes Kubelet
Documentation=https://kubernetes.io/docs/home/
After=containerd.service

[Service]
ExecStart=/usr/local/bin/kubelet \
  --config=/var/lib/kubelet/config.yaml \
  --kubeconfig=/etc/kubernetes/kubelet.conf \
  --hostname-override=master \
  --v=2
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable --now kubelet
}

function start_kube_proxy() {
    cat >/etc/kubernetes/kube-proxy.conf <<EOF
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/kubernetes-ca.pem
    server: https://$master_ip:6443
  name: kubernetes
users:
- name: system:kube-proxy
  user:
    client-certificate: /etc/kubernetes/pki/kube-proxy.pem
    client-key: /etc/kubernetes/pki/kube-proxy-key.pem
contexts:
- context:
    cluster: kubernetes
    user: system:kube-proxy
  name: default
current-context: default
EOF
    cat >/etc/systemd/system/kube-proxy.service <<'EOF'
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://kubernetes.io/docs/home/
After=network.target

[Service]
ExecStart=/usr/local/bin/kube-proxy \
  --kubeconfig=/etc/kubernetes/kube-proxy.conf \
  --v=2
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable --now kube-proxy
}

function config_kubectl() {
    mkdir -p $HOME/.kube
    cat >$HOME/.kube/config <<EOF
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/kubernetes-ca.pem
    server: https://192.168.60.128:6443
  name: kubernetes
users:
- name: admin
  user:
    client-certificate: /etc/kubernetes/pki/admin.pem
    client-key: /etc/kubernetes/pki/admin-key.pem
contexts:
- context:
    cluster: kubernetes
    user: admin
  name: kubernetes-admin
current-context: kubernetes-admin
EOF
}

function delete_taint() {
    until kubectl get node master &>/dev/null; do sleep 2; done
    kubectl taint nodes master node.kubernetes.io/not-ready:NoSchedule-
}

function main() {
    install_k8s_binaries
    gencert_k8s_certs
    start_apiserver
    start_scheduler
    start_controller_manager
    start_kubelet
    start_kube_proxy
    config_kubectl
    delete_taint
    echo "k8s安装完成"
}

main "$@"

scripts/k8s/uninstall.sh

bash
#! /bin/bash

services=(
    "kube-apiserver"
    "kube-controller-manager"
    "kube-scheduler"
    "kubelet"
    "kube-proxy"
)

function stop_services() {
    for svc in "${services[@]}"; do
        systemctl disable --now "$svc" 2>/dev/null
    done
}

function remove_k8s_config() {
    # kubectl 配置
    rm -rf $HOME/.kube
    # kube-proxy
    rm -rf /etc/systemd/system/kube-proxy.service
    rm -rf /etc/kubernetes/kube-proxy.conf
    # kubelet
    rm -rf /etc/systemd/system/kubelet.service
    rm -rf /etc/kubernetes/kubelet.conf
    rm -rf /var/lib/kubelet
    # controller-manager
    rm -rf /etc/kubernetes/controller-manager.conf
    rm -rf /etc/systemd/system/kube-controller-manager.service
    # scheduler
    rm -rf /etc/kubernetes/scheduler.conf
    rm -rf /etc/systemd/system/kube-scheduler.service
    # apiserver
    rm -rf /etc/systemd/system/kube-apiserver.service
    # pki 证书
    rm -rf /etc/kubernetes/pki
    # 删除自动生成的目录
    rm -rf /var/log/kubernetes
    rm -rf /run/kubernetes
    systemctl daemon-reload
}

function remove_k8s_binaries() {
    rm -rf /usr/local/bin/kube*
}

function main() {
    stop_services
    remove_k8s_config
    remove_k8s_binaries
    echo "Kubernetes 卸载完成"
}

main "$@"

Calico ​

scripts/calico/calico.yaml

bash
kubectl apply -f calico.yaml

Calico 网络插件清单文件位于 scripts/calico/calico.yaml,可直接应用部署。

CoreDNS ​

scripts/coredns/install.sh

bash
#!/bin/bash

set -e

function coredns_install() {
  cat >coredns.yaml <<EOF
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
  - list
  - watch
- apiGroups:
  - "discovery.k8s.io"
  resources:
  - endpointslices
  verbs:
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.k8s.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 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . 8.8.8.8 8.8.4.4
        cache 30
        loop
        reload
        loadbalance
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
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:
        kubernetes.io/os: linux
      containers:
      - name: coredns
        image: coredns/coredns:1.11.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
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: 8181
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          readOnlyRootFilesystem: true
      dnsPolicy: Default
      volumes:
      - name: config-volume
        configMap:
          name: coredns
---
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.96.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.yaml
  echo "CoreDNS 部署完成,等待 Pod 就绪..."
  kubectl rollout status deployment/coredns -n kube-system --timeout=120s
  echo "CoreDNS 已就绪"
}

function main() {
  coredns_install
}

main "$@"

scripts/coredns/uninstall.sh

bash
#! /bin/bash
# curl -x http://192.168.60.1:12450  -o coredns.yaml -L https://raw.githubusercontent.com/coredns/deployment/refs/heads/master/kubernetes/coredns.yaml.sed

function coredns_uninstall() {
  kubectl delete -f coredns.yaml --ignore-not-found=true
  rm -rf coredns.yaml
}

function main() {
  coredns_uninstall
}

main "$@"

基于 MIT 许可发布