当前位置 博文首页 > 尚墨:Rancher On K3s 高可用架构部署

    尚墨:Rancher On K3s 高可用架构部署

    作者:尚墨 时间:2021-01-30 15:35

    Rancher 推荐部署架构

    k3s 模式

    RKE 和 k8s 模式

    备注:
    我对 RKE 的理解就是 Ansible + kubeadm 的打包,首先 rke 需要到每一个节点都可以免密 ssh ,其次,可以使用类似 kubeadm-config.yaml 的配置文件 init 一个 k8s 集群。当然 rke 可以有效的管理证书。

    高可用模式下,一句大白话:无论如何你都需要 Rancher on K8s

    k3s 部署

    etcd 部署

    k3s 支持多种外部存储,例如:SQLite, MySQL,PostgSQL,etcd。Why is etcd?
    etcd: 高可用部署方便,集群管理方便,没有复杂的主从库搭建,加上 k8s 集群本身就需要维护 etcd ,所以维护成本较低。
    目前 Rancher 官方认证的版本是 etcd v3.3.15
    选择数据库

    # 准备 3 个节点部署 etcd
    wget  https://github.com/etcd-io/etcd/releases/download/v3.3.15/etcd-v3.3.15-linux-amd64.tar.gz
    tar xzvf etcd-v3.3.15-linux-amd64.tar.gz -C /data/das/
    cp /data/das/k3s-init/etcd-v3.3.15-linux-amd64/etc* /usr/loca/bin
    # 创建 etcd.service 服务托管于 systemd
    vim /usr/lib/systemd/system/etcd.service
    # 创建 etcd 配置文件
    vim /usr/loca/etcd/config
    # 启动 etcd
    systemctl daemon-reload
    systemctl start etcd
    systemctl enable etcd
    
    [Unit]
    Description=Etcd Server
    After=network.target
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=notify
    # 指定环境变量所在 
    EnvironmentFile=-/usr/local/etcd/config
    ExecStart=/usr/local/bin/etcd \
    --name=${ETCD_NAME} \
    --data-dir=${ETCD_DATA_DIR} \
    --listen-peer-urls=${ETCD_LISTEN_PEER_URLS} \
    --listen-client-urls=${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 \
    --advertise-client-urls=${ETCD_ADVERTISE_CLIENT_URLS} \
    --initial-advertise-peer-urls=${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
    --initial-cluster=${ETCD_INITIAL_CLUSTER} \
    --initial-cluster-token=${ETCD_INITIAL_CLUSTER} \
    --initial-cluster-state=new 
    Restart=on-failure
    LimitNOFILE=65536
    
    [Install]
    WantedBy=multi-user.target
    
    #[Member]
    ##节点名字
    ETCD_NAME="etcd01" 
    #数据目录
    ETCD_DATA_DIR="/data/etcd/"
    #当前节点的ip地址
    ETCD_LISTEN_PEER_URLS="http://192.168.1.1:2380" 
    ETCD_LISTEN_CLIENT_URLS="http://192.168.1.1:2379"
    
    #[Clustering]
    ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.1:2380"
    ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.1:2379"
    #集群所有的节点的ip地址
    ETCD_INITIAL_CLUSTER="etcd01=http://192.168.1.1:2380,etcd02=http://192.168.1.2:2380,etcd03=http://192.168.1.3:2380" 
    ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
    ETCD_INITIAL_CLUSTER_STATE="new"
    

    k3s 部署

    在两个节点上部署 k3s server

    # 下载部署脚本
    wget http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh  
    cp /data/das/k3s-init/k3s-install.sh /usr/local/bin/install.sh
    # 下载 k3s 镜像
    wget http://rancher-mirror.cnrancher.com/k3s/v1.18.2-k3s1/k3s-airgap-images-amd64.tar
    sudo mkdir -p /var/lib/rancher/k3s/agent/images/
    sudo cp ./k3s-airgap-images-amd64.tar /var/lib/rancher/k3s/agent/images/
    # 下载 k3s 二进制文件
    wget http://rancher-mirror.cnrancher.com/k3s/v1.18.2-k3s1/k3s
    cp /data/das/k3s-init/k3s /usr/local/bin/k3s
    # 执行 k3s 安装脚本
    # 跳过远程安装
    INSTALL_K3S_SKIP_DOWNLOAD=true  \
    # 集群名称
    INSTALL_K3S_NAME=rancher-server \
    # rancher server 参数配置 --docker 使用 docker 作为容器运行时,--bind-address 绑定节点 
    INSTALL_K3S_EXEC='server --docker --bind-address=10.50.26.252 --private-registry=https://registry.mydoman.com/rancher-server --write-kubeconfig=/root/.kube/config --write-kubeconfig-mode=644 --node-label asrole=worker --datastore-endpoint="http://10.50.26.252:2379,http://10.50.26.145:2379,http://10.50.26.235:2379" ' \
    install.sh
    # 检查 k3s-rancher-server 服务是否正常
    systemctl status k3s-rancher-server
    # 等大概 5分钟左右,查看 k3s 集群是否启动成功 
    kubectl get pods -A
    

    rancher 部署

    自签证,Rancher 官方提供了非常完善的签证脚本
    签证

    #!/bin/bash -e
    help ()
    {
        echo  ' ================================================================ '
        echo  ' --ssl-domain: 生成ssl证书需要的主域名,如不指定则默认为www.rancher.local,如果是ip访问服务,则可忽略;'
        echo  ' --ssl-trusted-ip: 一般ssl证书只信任域名的访问请求,有时候需要使用ip去访问server,那么需要给ssl证书添加扩展IP,多个IP用逗号隔开;'
        echo  ' --ssl-trusted-domain: 如果想多个域名访问,则添加扩展域名(SSL_TRUSTED_DOMAIN),多个扩展域名用逗号隔开;'
        echo  ' --ssl-size: ssl加密位数,默认2048;'
        echo  ' --ssl-cn: 国家代码(2个字母的代号),默认CN;'
        echo  ' 使用示例:'
        echo  ' ./create_self-signed-cert.sh --ssl-domain=www.test.com --ssl-trusted-domain=www.test2.com \ '
        echo  ' --ssl-trusted-ip=1.1.1.1,2.2.2.2,3.3.3.3 --ssl-size=2048 --ssl-date=3650'
        echo  ' ================================================================'
    }
    
    case "$1" in
        -h|--help) help; exit;;
    esac
    
    if [[ $1 == '' ]];then
        help;
        exit;
    fi
    
    CMDOPTS="$*"
    for OPTS in $CMDOPTS;
    do
        key=$(echo ${OPTS} | awk -F"=" '{print $1}' )
        value=$(echo ${OPTS} | awk -F"=" '{print $2}' )
        case "$key" in
            --ssl-domain) SSL_DOMAIN=$value ;;
            --ssl-trusted-ip) SSL_TRUSTED_IP=$value ;;
            --ssl-trusted-domain) SSL_TRUSTED_DOMAIN=$value ;;
            --ssl-size) SSL_SIZE=$value ;;
            --ssl-date) SSL_DATE=$value ;;
            --ca-date) CA_DATE=$value ;;
            --ssl-cn) CN=$value ;;
        esac
    done
    
    # CA相关配置
    CA_DATE=${CA_DATE:-3650}
    CA_KEY=${CA_KEY:-cakey.pem}
    CA_CERT=${CA_CERT:-cacerts.pem}
    CA_DOMAIN=cattle-ca
    
    # ssl相关配置
    SSL_CONFIG=${SSL_CONFIG:-$PWD/openssl.cnf}
    SSL_DOMAIN=${SSL_DOMAIN:-'www.rancher.local'}
    SSL_DATE=${SSL_DATE:-3650}
    SSL_SIZE=${SSL_SIZE:-2048}
    
    ## 国家代码(2个字母的代号),默认CN;
    CN=${CN:-CN}
    
    SSL_KEY=$SSL_DOMAIN.key
    SSL_CSR=$SSL_DOMAIN.csr
    SSL_CERT=$SSL_DOMAIN.crt
    
    echo -e "\033[32m ---------------------------- \033[0m"
    echo -e "\033[32m       | 生成 SSL Cert |       \033[0m"
    echo -e "\033[32m ---------------------------- \033[0m"
    
    if [[ -e ./${CA_KEY} ]]; then
        echo -e "\033[32m ====> 1. 发现已存在CA私钥,备份"${CA_KEY}"为"${CA_KEY}"-bak,然后重新创建 \033[0m"
        mv ${CA_KEY} "${CA_KEY}"-bak
        openssl genrsa -out ${CA_KEY} ${SSL_SIZE}
    else
        echo -e "\033[32m ====> 1. 生成新的CA私钥 ${CA_KEY} \033[0m"
        openssl genrsa -out ${CA_KEY} ${SSL_SIZE}
    fi
    
    if [[ -e ./${CA_CERT} ]]; then
        echo -e "\033[32m ====> 2. 发现已存在CA证书,先备份"${CA_CERT}"为"${CA_CERT}"-bak,然后重新创建 \033[0m"
        mv ${CA_CERT} "${CA_CERT}"-bak
        openssl req -x509 -sha256 -new -nodes -key ${CA_KEY} -days ${CA_DATE} -out ${CA_CERT} -subj "/C=${CN}/CN=${CA_DOMAIN}"
    else
        echo -e "\033[32m ====> 2. 生成新的CA证书 ${CA_CERT} \033[0m"
        openssl req -x509 -sha256 -new -nodes -key ${CA_KEY} -days ${CA_DATE} -out ${CA_CERT} -subj "/C=${CN}/CN=${CA_DOMAIN}"
    fi
    
    echo -e "\033[32m ====> 3. 生成Openssl配置文件 ${SSL_CONFIG} \033[0m"
    cat > ${SSL_CONFIG} <<EOM
    [req]
    req_extensions = v3_req
    distinguished_name = req_distinguished_name
    [req_distinguished_name]
    [ v3_req ]
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    extendedKeyUsage = clientAuth, serverAuth
    EOM
    
    if [[ -n ${SSL_TRUSTED_IP} || -n ${SSL_TRUSTED_DOMAIN} ]]; then
        cat >> ${SSL_CONFIG} <<EOM
    subjectAltName = @alt_names
    [alt_names]
    EOM
        IFS=","
        dns=(${SSL_TRUSTED_DOMAIN})
        dns+=(${SSL_DOMAIN})
        for i in "${!dns[@]}"; do
          echo DNS.$((i+1)) = ${dns[$i]} >> ${SSL_CONFIG}
        done
    
        if [[ -n ${SSL_TRUSTED_IP} ]]; then
            ip=(${SSL_TRUSTED_IP})
            for i in "${!ip[@]}"; do
              echo IP.$((i+1)) = ${ip[$i]} >> ${SSL_CONFIG}
            done
        fi
    fi
    
    echo -e "\033[32m ====> 4. 生成服务SSL KEY ${SSL_KEY} \033[0m"
    openssl genrsa -out ${SSL_KEY} ${SSL_SIZE}
    
    echo -e "\033[32m ====> 5. 生成服务SSL CSR ${SSL_CSR} \033[0m"
    openssl req -sha256 -new -key ${SSL_KEY} -out ${SSL_CSR} -subj "/C=${CN}/CN=${SSL_DOMAIN}" -config ${SSL_CONFIG}
    
    echo -e "\033[32m ====> 6. 生成服务SSL CERT ${SSL_CERT} \033[0m"
    openssl x509 -sha256 -req -in ${SSL_CSR} -CA ${CA_CERT} \
        -CAkey ${CA_KEY} -CAcreateserial -out ${SSL_CERT} \
        -days ${SSL_DATE} -extensions v3_req \
        -extfile ${SSL_CONFIG}
    
    echo -e "\033[32m ====> 7. 证书制作完成 \033[0m"
    echo
    echo -e "\033[32m ====> 8. 以YAML格式输出结果 \033[0m"
    echo "----------------------------------------------------------"
    echo "ca_key: |"
    cat $CA_KEY | sed 's/^/  /'
    echo
    echo "ca_cert: |"
    cat $CA_CERT | sed 's/^/  /'
    echo
    echo "ssl_key: |"
    cat $SSL_KEY | sed 's/^/  /'
    echo
    echo "ssl_csr: |"
    cat $SSL_CSR | sed 's/^/  /'
    echo
    echo "ssl_cert: |"
    cat $SSL_CERT | sed 's/^/  /'
    echo
    
    echo -e "\033[32m ====> 9. 附加CA证书到Cert文件 \033[0m"
    cat ${CA_CERT} >> ${SSL_CERT}
    echo "ssl_cert: |"
    cat $SSL_CERT | sed 's/^/  /'
    echo
    
    echo -e "\033[32m ====> 10. 重命名服务证书 \033[0m"
    echo "cp ${SSL_DOMAIN}.key tls.key"
    cp ${SSL_DOMAIN}.key tls.key
    echo "cp ${SSL_DOMAIN}.crt tls.crt"
    cp ${SSL_DOMAIN}.crt tls.crt
    
    mkdir /data/das/rancher-key
    cd /data/das/rancher-key
    # 执行自签证脚本
    ./key-create.sh --ssl-domain=rancher.mydoman.com --ssl-truted-ip=<RANCHER_LB_IP>
    # 验证是否成功
    openssl verify -CAfile cacerts.pem tls.cr
    openssl x509 -in tls.crt -noout -text
    

    Rancher 部署

    # 安装 helm 
    wget http://rancher-mirror.cnrancher.com/helm/v3.4.0/helm-v3.4.0-linux-amd64.tar.gz
    tar zxvf helm-v3.4.0-linux-amd64.tar.gz -C /data/das/
    cp /data/das/linux-amd64/helm /usr/local/bin/ 
    # 创建命名空间
    kubectl  create namespace cattle-system
    # ca证书密文
    kubectl -n cattle-system create secret tls tls-rancher-ingress --cert=/data/das/rancher-key/tls.crt --key=/data/das/rancher-key/tls.key 
    kubectl -n cattle-system create secret generic tls-ca --from-file=cacerts.pem
    # 添加 chat 仓库,推荐添加 stable 稳定版仓库,如果需要固定版本可以去 http://mirror.cnrancher.com/ 上面下载
    helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
    # helm install rancher 
    helm install rancher rancher-stable/rancher \
    -n cattle-system \
    # 使用自签证
    --set ingress.tls.source=secret \
    # 是否使用自签证
    --set privateCA=true \
    --set additionalTrustedCAs=true \
    --set hostname=rancher.mydoman.com
    # 验证是否安装成功
    helm list -n cattle-system 
    # 检查 rancher 服务运行是否正常
    kubectl -n cattle-system get pods
    # 查看 ingress 地址
    kubectl -n cattle-system get ingress  
    

    填坑之旅

    现象:
    通过 ingress 地址访问 rancher 报 404 等错误
    解决方式:
    修改 k3s 自带的 traefik deployment 启动参数

    ……
      spec:
          containers:
          - args:
            - --configfile=/config/traefik.toml
            # 添加这一行
            - --rancher
            image: rancher/library-traefik:1.7.19
            imagePullPolicy: IfNotPresent
    ……
    

    现象:
    导入集群 cattle-system 报错 http://yourdomain.com 无法解析,不可达
    原因:
    没有做域名解析
    解决方式:

    kubectl -n cattle-system edit deployments.apps cattle-cluster-agent 
    
    # 在 cattle-cluster-agent 添加 host 映射
    ……
        spec:
          hostAliases:
          - hostnames:
            - yourdomain.com
            ip: 192.168.1.1
    ……
    

    现象:
    k3s 使用 docker 启动报错,有异常
    原因:
    docker 使用 systemd cgroup 驱动管理 cgroup
    解决方式:

    vim /etc/docker/daemon.json
    systemctl restart docker
    
    { 
    # 删除 exec-opts 配置
    "exec-opts": ["native.cgroupdriver=systemd"], 
    "log-driver": "json-file",
    "log-opts": { 
       "max-size": "100m",
       "max-file": "3"
      } ,
     "data-root": "/data/docker",
    "registry-mirrors": ["https://15v8lrgz.mirror.aliyuncs.com"],
    "insecure-registries":[
      "https://registry.mydoman.com"
     ]
    }
    

    参考文献

    traefik 官方对 Rancher 有额外支持 备注:具体参数加什么,需要加上之后 kubectl -n kube-system logs traefik-<DEPLOYMENT_ID>-<POD_ID> 看一下报错,现在 k3s 默认安装 traefik v1.5
    Rancher官方TLS自签证帮助文档
    RancherServer 推荐部署架构
    k3s 离线安装
    k3s 数据存储选项
    Rancher中国区仓库备注:常用 k8s 版本都有
    Rancher在阿里云的镜像仓库备注:中国区仓库里面 /rancher/v/ 里面会有 image-list.txt 这些 image 前面加上镜像仓库地址,基本都可以拉得到镜像