K8S通过Ansible安装集群

news2024/11/25 0:34:26

K8S通过Ansible安装集群

K8S集群安装可参考https://gitee.com/open-hand/kubeadm-ha.git、https://github.com/easzlab/kubeasz.git

安装高可用集群

git clone https://gitee.com/open-hand/kubeadm-ha.git && cd kubeadm-ha

升级内核,非必需,默认不升级,若需要升级执行如下命令

ansible-playbook -i example/hosts.m-master.ip.ini 00-kernel.yml

hosts.m-master.ip.ini

此文件为配置主机分组及必要变量。需要按需求维护各个分组的主机,例如etcd节点主机、master节点主机、工作节点主机等。ansible将根据配置的各个分组的主机,安装对应分组的Kubernetes组件

; 将所有节点的信息在这里填写
;    第一个字段                  为节点内网IP,部署完成后为 kubernetes 节点 nodeName
;    第二个字段 ansible_port     为节点 sshd 监听端口
;    第三个字段 ansible_user     为节点远程登录用户名
;    第四个字段 ansible_ssh_pass 为节点远程登录用户密码
[all]
172.23.17.105 ansible_port=22 ansible_user="root" ansible_ssh_pass="sBzrmwcJwjGLXu&P"

; 私有云:
;    VIP 负载模式:
;       也就是负载均衡器 + keepalived 模式,比如常用的 haproxy + keepalived。
;       本脚本中负载均衡器有 nginx、openresty、haproxy、envoy 可供选择,设置 lb_mode 即可进行任意切换。
;       设置 lb_kube_apiserver_ip 即表示启用 keepalived,请先与服务器提供部门协商保留一个IP作为 lb_kube_apiserver_ip,
;       一般 lb 节点组中有两个节点就够了,lb节点组中第一个节点为 keepalived 的 master 节点,剩下的都为 backed 节点。
;
;    节点本地负载模式:
;       只启动负载均衡器,不启用 keepalived(即不设置 lb_kube_apiserver_ip),
;       此时 kubelet 链接 apiserver 地址为 127.0.0.1:lb_kube_apiserver_port。
;       使用此模式时请将 lb 节点组置空。
;
; 公有云:
;    不推荐使用 slb 模式,建议直接使用节点本地负载模式。
;    若使用 slb 模式,请先使用节点本地负载模式进行部署,
;    部署成功后再切换至 slb 模式:
;       将 lb_mode 修改为 slb,将 lb_kube_apiserver_ip 设置为购买到的 slb 内网ip,
;       修改 lb_kube_apiserver_port 为 slb 监听端口。
;    再次运行初始化集群脚本即可切换至 slb 模式。
[lb]

; 注意etcd集群必须是1,3,5,7...奇数个节点
[etcd]
172.23.17.105

[kube-master]
172.23.17.105

[kube-worker]
172.23.17.105

; 预留组,后续添加master节点使用
[new-master]

; 预留组,后续添加worker节点使用
[new-worker]

; 预留组,后续添加etcd节点使用
[new-etcd]

; 预留组,后续删除worker角色使用
[del-worker]

; 预留组,后续删除master角色使用
[del-master]

; 预留组,后续删除etcd角色使用
[del-etcd]

; 预留组,后续删除节点使用
[del-node]

;-------------------------------------- 以下为基础信息配置 ------------------------------------;
[all:vars]
; 是否跳过节点物理资源校验,Master节点要求2c2g以上,Worker节点要求2c4g以上
skip_verify_node=false
; kubernetes版本
kube_version="1.21.14"

; 容器运行时类型,可选项:containerd,docker;默认 containerd
container_manager="containerd"

; 负载均衡器
;   有 nginx、openresty、haproxy、envoy  和 slb 可选,默认使用 nginx
lb_mode="nginx"
; 使用负载均衡后集群 apiserver ip,设置 lb_kube_apiserver_ip 变量,则启用负载均衡器 + keepalived
; lb_kube_apiserver_ip="192.168.56.15"
; 使用负载均衡后集群 apiserver port
lb_kube_apiserver_port="8443"

; 网段选择:pod 和 service 的网段不能与服务器网段重叠,
; 若有重叠请配置 `kube_pod_subnet` 和 `kube_service_subnet` 变量设置 pod 和 service 的网段,示例参考:
;    如果服务器网段为:10.0.0.1/8
;       pod 网段可设置为:192.168.0.0/18
;       service 网段可设置为 192.168.64.0/18
;    如果服务器网段为:172.16.0.1/12
;       pod 网段可设置为:10.244.0.0/18
;       service 网段可设置为 10.244.64.0/18
;    如果服务器网段为:192.168.0.1/16
;       pod 网段可设置为:10.244.0.0/18
;       service 网段可设置为 10.244.64.0/18
; 集群pod ip段,默认掩码位 18 即 16384 个ip
kube_pod_subnet="10.244.0.0/18"
; 集群service ip段
kube_service_subnet="10.244.64.0/18"
; 分配给节点的 pod 子网掩码位,默认为 24 即 256 个ip,故使用这些默认值可以纳管 16384/256=64 个节点。
kube_network_node_prefix="24"

; node节点最大 pod 数。数量与分配给节点的 pod 子网有关,ip 数应大于 pod 数。
; https://cloud.google.com/kubernetes-engine/docs/how-to/flexible-pod-cidr
kube_max_pods="110"

; 集群网络插件,目前支持flannel,calico
network_plugin="calico"

; 若服务器磁盘分为系统盘与数据盘,请修改以下路径至数据盘自定义的目录。
; Kubelet 根目录
kubelet_root_dir="/var/lib/kubelet"
; docker容器存储目录
docker_storage_dir="/var/lib/docker"
; containerd容器存储目录
containerd_storage_dir="/var/lib/containerd"
; Etcd 数据根目录
etcd_data_dir="/var/lib/etcd"
  • 注意最后设置安装kubelet、docker、etcd、containerd路径配置,需要根据需求规划好目录,分配充足的磁盘空间,否则当磁盘紧张时会自定在节点上打上磁盘压力污点,没有容忍此污点的pod将不能调度到此节点

00-kernel.yml

# 升级所有节点内核
- hosts: all
  gather_facts: false
  tasks:
    - name: "设置代理服务器环境变量"
      set_fact:
        proxy_env:
          http_proxy: "{{ http_proxy | default ('') }}"
          HTTP_PROXY: "{{ http_proxy | default ('') }}"
          https_proxy: "{{ https_proxy | default ('') }}"
          HTTPS_PROXY: "{{ https_proxy | default ('') }}"
          no_proxy: "{{ no_proxy | default ('') }}"
          NO_PROXY: "{{ no_proxy | default ('') }}"
      no_log: true

- hosts: 
  - all
  roles:
  - prepare/variables
  - prepare/base
  - prepare/kernel
  environment: "{{ proxy_env }}"
  • set_fact:用于在tasks模块中定义变量

  • environment:用于设置环境变量

  • roles:将会执行roles目录下指定目录的tasks

    • variables: 设置变量,可在roles/prepare/variables/defaults/main.yml编辑修改

    • base: 完成变量校验、节点校验、完成基础软件安装。main.yml可以查看task的执行流程

    • kernel:升级系统内核。main.yml可以查看task的执行流程

安装高可用Kubernetes集群

执行如下指令

ansible-playbook -i example/hosts.m-master.ip.ini 90-init-cluster.yml

90-init-cluster.yml

# 校验节点软件系统及硬件系统、安装必要基础组件、docker、kubeadm、kubelet、kubectl
- hosts: 
  - all
  gather_facts: false
  tasks:
    - name: "设置代理服务器环境变量"
      set_fact:
        proxy_env:
          http_proxy: "{{ http_proxy | default ('') }}"
          HTTP_PROXY: "{{ http_proxy | default ('') }}"
          https_proxy: "{{ https_proxy | default ('') }}"
          HTTPS_PROXY: "{{ https_proxy | default ('') }}"
          no_proxy: "{{ no_proxy | default ('') }}"
          NO_PROXY: "{{ no_proxy | default ('') }}"
      no_log: true

- hosts: 
  - all
  roles:
  - prepare/variables
  - prepare/base
  - prepare/container-engine
  - prepare/kubernetes
  environment: "{{ proxy_env }}"

# 进行 apiserver 负载均衡
- hosts: 
  - all
  roles:
  - prepare/variables
  - load-balancer

- hosts: 
  - all
  roles:
  - prepare/variables
  - chrony

# 安装 etcd,并分发etcd证书到master节点
- hosts: 
  - etcd
  - new-etcd
  - kube-master
  - new-master
  roles:
  - prepare/variables
  - etcd/certificates
  - etcd/install

# 生成 kubernetes 所需证书证书
- hosts: 
  - kube-master
  - new-master
  - kube-worker
  - new-worker
  roles:
  - prepare/variables
  - kube-certificates

# 初始化master节点
- hosts: 
  - kube-master
  - new-master
  roles:
  - prepare/variables
  - kube-master

# 初始化worker节点
- hosts: 
  - kube-worker
  - new-worker
  roles:
  - prepare/variables
  - kube-worker

# 标记各节点角色
- hosts: 
  - kube-master
  - kube-worker
  - new-master
  - new-worker
  roles:
  - prepare/variables
  - post

# 安装基础插件
- hosts: 
  - kube-master[0]
  roles:
  - prepare/variables
  - plugins/network-plugins
  - plugins/ingress-controller
  - plugins/metrics-server
  - plugins/kubernetes-dashboard
  - plugins/cert-manager
执行roles/prepare/container-engine

tasks目录下main.yml文件说明了执行的流程

- name: 判断 Docker 是否早已安装
  shell: >
    systemctl status docker | grep running || echo "not running"
  register: docker_already_running

- name: 判断 containerd 是否早已安装
  shell: >
    systemctl status containerd | grep running || echo "not running"
  register: containerd_already_running

- include_tasks: docker/main.yml
  when: 
  - container_manager == "docker"
  - '"active" not in docker_already_running.stdout'
  - '"active" not in containerd_already_running.stdout'

- include_tasks: containerd/main.yml
  when: 
  - container_manager == "containerd"
  - '"active" not in docker_already_running.stdout'
  - '"active" not in containerd_already_running.stdout'
  • 首先获取docker、containerd服务的运行状态。systemctl status docker的输出作为grep running的输入。如果未运行则显示not running,并注册运行变量

  • 根据container_manager及安装状态确定执行docker下任务,还是containerd下任务。when下多个条件列表是and关系。如果目标主机已经安装容器将不会再安装

docker/main.yml
# 系统基础软件环境
- include_tasks: centos.yml
  when: ansible_distribution in [ 'CentOS','OracleLinux','RedHat' ]

- include_tasks: debian.yml
  when: ansible_distribution in [ 'Ubuntu','Debian' ]

# 公共系统参数设置
- include_tasks: common.yml
  • 根据不同操作系统执行对应操作系统安装

    • centos.yml

      - name: 添加 Docker yum 仓库
        yum_repository:
          name: docker-ce-stable
          file: docker-ce
          description: Docker CE Stable - $basearch
          baseurl: "{{ docker_yum_repo }}"
          enabled: no
          gpgcheck: no
          state: present
      
      - name: 安装 Docker
        yum:
          name:
          - "docker-ce-{{ docker_version }}.ce"
            state: present
            enablerepo: docker-ce-stable
        when: docker_version is version('18.09', '<')
      
      - name: 安装 Docker
        yum:
          name:
          - "docker-ce-{{ docker_version }}"
          - "docker-ce-cli-{{ docker_version }}"
          - "containerd.io-{{ containerd_version.split('-')[0] }}"
            state: present
            enablerepo: docker-ce-stable
        when: docker_version is version('18.09', '>=')
      
      • 通过yum_repository模块添加 Docker yum 仓库

        • name:必须参数,指定唯一的仓库ID,state为present或absent时需要设置name参数

        • file:用于设置仓库的配置文件名称,即设置”.repo”配置文件的文件名前缀,在不使用此参数的情况下,默认以 name 参数的仓库ID作为”.repo”配置文件的文件名前缀,同一个”.repo” 配置文件中可以存在多个yum源

        • description:仓库的注释信息

        • baseurl:yum仓库repodata目录的URL,可以是多个,如果设置为多个,需要使用"metalink"和"mirrorlist"参数

        • enabled:是否使用此yum仓库

        • gpgcheck:是否对软件包执行gpg签名检查

        • state:状态,默认的present为安装此yum仓库,absent为删除此yum仓库

      • 通过yum安装docker

        • 如果docker_version小于18.09,则执行docker-ce-{{ docker_version }}.ce安装

          - name: 安装 Docker
            yum:
            name:
            - "docker-ce-{{ docker_version }}.ce"
              state: present
              enablerepo: docker-ce-stable
              when: docker_version is version('18.09', '<')
          
          • enablerepo:启用源

          • state:状态(absent、installed、latest、present、removed)。present和installed将简单地确保安装所需的包;latest如果指定的程序包不是最新的可用版本,将更新该程序包;absent和removed将删除指定的程序包

          • name:要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径

        • 如果docker_version大于等于18.09,则执行docker-ce-{{ docker_version }}、docker-ce-cli-{{ docker_version }}、containerd.io-{{ containerd_version.split(‘-’)[0] }}

            - name: 安装 Docker
              yum:
                name:
                - "docker-ce-{{ docker_version }}"
                - "docker-ce-cli-{{ docker_version }}"
                - "containerd.io-{{ containerd_version.split('-')[0] }}"
                state: present
                enablerepo: docker-ce-stable
              when: docker_version is version('18.09', '>=')
          
    • debian.yml

      - name: 生成 Docker GPG 公钥
        copy:
          src: docker.gpg
          dest: /tmp/docker.gpg
          owner: root
          mode: 0644
      
      - name: 添加 Docker GPG 公钥
        shell: apt-key add /tmp/docker.gpg
        
      - name: 添加 Docker apt 仓库
        apt_repository:
          repo: "{{ docker_apt_repo }}"
          state: present
        
      - name: 安装 Docker
        apt:
          name:
          - "docker-ce={{ docker_version }}~ce~3-0~{{ ansible_distribution | lower }}"
          state: present
          allow_unauthenticated: true
        when: docker_version is version('18.09', '<')
        
      - name: 安装 Docker
        apt:
          name:
          - "docker-ce=5:{{ docker_version }}~3-0~{{ ansible_distribution | lower }}-{{ ansible_distribution_release }}"
          - "docker-ce-cli=5:{{ docker_version }}~3-0~{{ ansible_distribution | lower }}-{{ ansible_distribution_release }}"
          - "containerd.io={{ containerd_version }}"
          state: present
          allow_unauthenticated: true
        when: docker_version is version('18.09', '>=')
      
      • 类似于centos.yml,完成docker安装
  • common.yml。为安装的docker设置系统参数

    • 完成目录创建,如:{{ docker_storage_dir }} 存储目录

    • 设置docker开机自启动

    • 添加当前用户到Docker用户组

containerd/main.yml

类似于上述docker安装流程,根据不同操作系统,使用对应包管理工具执行containerd安装

# 系统基础软件环境
- include_tasks: centos.yml
  when: ansible_distribution in [ 'CentOS','OracleLinux','RedHat' ]

- include_tasks: debian.yml
  when: ansible_distribution in [ 'Ubuntu','Debian' ]

# 公共系统参数设置
- include_tasks: common.yml
执行roles/prepare/kubernetes完成kubernetes安装

根据main.yml文件可知安装kubernetes流程,类似于docker安装流程

# 系统基础软件环境
- include_tasks: centos.yml
  when: ansible_distribution in [ 'CentOS','OracleLinux','RedHat' ]

- include_tasks: debian.yml
  when: ansible_distribution in [ 'Ubuntu','Debian' ]

- name: 配置 kubectl 命令行自动补全
  shell: kubectl completion bash > /usr/share/bash-completion/completions/kubectl
  • 根据操作系统执行kubernetes安装
centos.yml

CentOS、OracleLinux、RedHat执行安装kubernetes流程如下

- name: 添加 Kubernetes yum 仓库
  yum_repository:
    name: kubernetes
    file: kubernetes
    description: Kubernetes
    baseurl: "{{ kubernetes_yum_repo }}"
    enabled: no
    gpgcheck: no
    state: present

- name: 安装 kubeadm kubelet kubectl
  yum:
    name: 
    - "kubectl-{{ kube_version }}"
    - "kubelet-{{ kube_version }}"
    - "kubeadm-{{ kube_version }}"
    state: present
    enablerepo: kubernetes
  • 设置Kubernetes yum仓库

  • 安装kubeadm kubelet kubectl

    • 用来初始化集群的指令

    • 在集群中的每个节点上用来启动 Pod 和容器等

    • 用来与集群通信的命令行工具

debian.yml

Ubuntu、Debian执行安装kubernetes流程如下

- name: 生成 Kubernetes GPG 公钥
  copy:
    src: kubernetes.gpg
    dest: /tmp/kubernetes.gpg
    owner: root
    mode: 0644

- name: 添加 Kubernetes GPG 公钥
  shell: apt-key add /tmp/kubernetes.gpg

- name: 添加 Kubernetes apt 仓库
  apt_repository:
    repo: "{{ kubernetes_apt_repo }}"
    state: present

- name: 安装 kubeadm kubelet kubectl
  apt: 
    name:
    - "kubectl={{ kube_version }}-00"
    - "kubelet={{ kube_version }}-00"
    - "kubeadm={{ kube_version }}-00"
    state: present
    allow_unauthenticated: true
  • 类似于centos.yml安装流程,只是改为用apt包管理器安装
apiserver 负载均衡安装
- hosts: 
  - all
  roles:
  - prepare/variables
  - load-balancer
load-balancer

查看main.yml,了解安装流程

- include_tasks: external.yml
  when: lb_mode == "slb"

- include_tasks: internal.yml
  when: 
  - lb_mode != "slb"
  - (inventory_hostname in groups['lb']) or (groups['lb']|length == 0 and inventory_hostname in (groups['kube-master'] + groups['kube-worker'] + groups['new-master'] + groups['new-worker']))
  • lb_mode:默认为nginx,支持nginx、openresty、haproxy、envoy、slb

  • 对于lb_mode为非slb类型,如果配置lb节点列表,则只在lb节点列表执行internal.yml任务;如果未配置,则在kube-master、kube-worker、new-master、new-worker下节点执行internal.yml任务

####### internal.yml

- name: 判断 Docker 是否早已安装
  shell: >
    systemctl status docker | grep running || echo "not running"
  register: docker_already_running

- name: 设置 container_manager_detected 变量
  set_fact:
    container_manager_detected: >-
      {%- if "active" in docker_already_running.stdout -%}
      docker
      {%- else -%}
      containerd
      {%- endif -%}

- name: 创建 load-balancer、kubelet 相关目录
  file: 
    name: "{{ item }}"
    state: directory
  with_items:
  - "{{ kubelet_root_dir }}"
  - /etc/kubernetes/manifests
  - /etc/kubernetes/plugins/lb-config
  - /etc/systemd/system/kubelet.service.d

- include_tasks: openresty.yml
  when: lb_mode == "openresty"

- include_tasks: nginx.yml
  when: lb_mode == "nginx"

- include_tasks: haproxy.yml
  when: lb_mode == "haproxy"

- include_tasks: envoy.yml
  when: lb_mode == "envoy"

- block:
  - name: keepalived | 获取网卡名称
    shell: "ip a|grep '{{ current_host_ip }}/'|awk '{print $NF}'"
    register: lb_keepalived_interface
  - name: keepalived | 拉取相关镜像
    shell: "{{ image_pull_command }} {{ item }}"
    with_items:
    - "{{ lb_keepalived_image }}"
  - name: keepalived | 生成 static pod 文件
    template: 
      src: keepalived.yaml.j2
      dest: /etc/kubernetes/manifests/lb-keepalived.yaml
      owner: root
      mode: 0644
  when: inventory_hostname in groups['lb']

- name: 读取 kubelet.conf 文件 stat 信息
  stat: 
    path: /etc/kubernetes/kubelet.conf
  register: kubelet_conf_stat

- block:
  - name: 获取 Docker Cgroup Driver 值
    shell: docker info --format '{{ '{{' }} json .CgroupDriver {{ '}}' }}' | cut -d'"' -f2
    register: docker_cgroup_driver
    when: container_manager_detected == 'docker'

  - name: 设置 docker 为容器运行时 kubelet_cgroup_driver_detected 变量
    set_fact:
      kubelet_cgroup_driver_detected: >-
        {{ docker_cgroup_driver.stdout }}
    when: container_manager_detected == 'docker'

  - name: 设置 containerd 为容器运行时 kubelet_cgroup_driver_detected 变量
    set_fact:
      kubelet_cgroup_driver_detected: >-
        {%- if containerd_use_systemd_cgroup -%}systemd{%- else -%}cgroupfs{%- endif -%}
    when: container_manager_detected == 'containerd'

  - name: 生成临时 kubelet unit 文件
    template: 
      src: 20-kubelet-override.conf.j2
      dest: /etc/systemd/system/kubelet.service.d/20-kubelet-override.conf
      owner: root
      mode: 0644

  - name: 重新加载 daemon
    systemd:
      daemon_reload: yes

  - name: 临时启动 kubelet 以引导 lb 运行
    service:
      name: kubelet
      state: restarted
      enabled: yes

  when: 
  - not kubelet_conf_stat.stat.exists

- name: 以轮询的方式等待 {{ lb_mode }} 运行完成
  shell: nc -z -w 3 127.0.0.1 {{ lb_kube_apiserver_port }}
  register: lb_status
  until: lb_status.rc == 0
  retries: 12
  delay: 5

- name: 以轮询的方式等待 keepalived 运行完成
  shell: nc -z -w 3 {{ kube_apiserver_ip | trim }} {{ lb_kube_apiserver_port }}
  register: keepalived_status
  until: keepalived_status.rc == 0
  retries: 12
  delay: 5
  when: inventory_hostname in groups['lb']

- block:
  - name: 移除临时 kubelet unit 文件
    file: 
      name: /etc/systemd/system/kubelet.service.d/20-kubelet-override.conf
      state: absent

  - name: 重新加载 daemon
    systemd:
      daemon_reload: yes

  - name: 停止临时启动 kubelet
    service:
      name: kubelet
      state: stopped
      enabled: yes
  when: 
  - not kubelet_conf_stat.stat.exists
  - inventory_hostname in (groups['kube-master'] + groups['kube-worker'] + groups['new-master'] + groups['new-worker'])
  • 创建相关目录:kubelet_root_dir配置kubernetes使用根目录

  • openresty.yml
    openresty是一个功能比较全的应用服务器,是基于标准的nginx核心,可以扩展很多第三方模块,是中国人章亦春发起,不管大小厂都会有它的深度用户,web开发人员可以使用lua编程语言,对核心以及各种c模块进行编程,可以利用openresty快速搭建超1万并发高性能web应用系统

    - name: Openresty lb | 生成 openresty lb 配置文件
      template:
        src: openresty/openresty.conf.j2
        dest: /etc/kubernetes/plugins/lb-config/nginx.conf
        owner: root
        mode: 0644
      register: lb_configuration_result
    
    - name: Openresty lb | 拉取相关镜像
      shell: "{{ image_pull_command }} {{ item }}"
      with_items:
      - "{{ lb_openresty_image }}"
      - "{{ pod_infra_container_image }}"
    
    - name: Openresty lb | 生成 openresty lb static pod 文件
      template:
        src: openresty/openresty.yaml.j2
        dest: /etc/kubernetes/manifests/lb-kube-apiserver.yaml
        owner: root
        mode: 0644
    
    • 使用template模块将tasks目录同级templates目录下openresty/openresty.conf.j2输出到节点主机/etc/kubernetes/plugins/lb-config/nginx.conf中

    • 如果想了解更多ansible各个模块详细信息可以通过ansible-doc查看,例如 执行 ansible-doc template即可查看template模块详细配置及解释

    • 拉取Openresty镜像及pause镜像

    • 在Kubernetes中pause容器被当作Pod中所有容器的“父容器”,并为每个业务容器提供以下功能(关于pause大家可以看Kubernetes网络权威指南)

      • 在Pod中作为共享Linux namespace(Network、UTS等)的基础

      • 启用PID namespace共享,为Pod提供1号进程,并收集Pod内的僵尸进程

    • 将templates目录下openresty/openresty.yaml.j2输出到/etc/kubernetes/manifests/lb-kube-apiserver.yaml中

  • nginx.yml

    - name: Nginx lb | 生成 nginx lb 配置文件
    template:
      src: nginx/nginx.conf.j2
      dest: /etc/kubernetes/plugins/lb-config/nginx.conf
      owner: root
      mode: 0644
    register: lb_configuration_result
    
    - name: Nginx lb | 拉取相关镜像
      shell: "{{ image_pull_command }} {{ item }}"
      with_items:
      - "{{ lb_nginx_image }}"
      - "{{ pod_infra_container_image }}"
    
    - name: Nginx lb | 生成 nginx lb static pod 文件
      template:
        src: nginx/nginx.yaml.j2
        dest: /etc/kubernetes/manifests/lb-kube-apiserver.yaml
        owner: root
        mode: 0644
    
    • 将templates目录下nginx/nginx.conf.j2输出到节点/etc/kubernetes/plugins/lb-config/nginx.conf中

    • 拉取nginx镜像和pause镜像

    • 将templates目录下nginx/nginx.yaml.j2输出到节点/etc/kubernetes/manifests/lb-kube-apiserver.yaml中

  • haproxy.yml
    Haproxy 是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。安装过程类似上面流程

    - name: Haproxy | 生成 haproxy 配置文件
    template: 
      src: haproxy/haproxy.cfg.j2 
      dest: /etc/kubernetes/plugins/lb-config/haproxy.cfg
      owner: root
      mode: 0644
    register: lb_configuration_result
    
    - name: Haproxy | 拉取相关镜像
      shell: "{{ image_pull_command }} {{ item }}"
      with_items:
      - "{{ lb_haproxy_image }}"
      - "{{ pod_infra_container_image }}"
    
    - name: Haproxy | 生成 haproxy static pod 文件
      template:
        src: haproxy/haproxy.yaml.j2
        dest: /etc/kubernetes/manifests/lb-kube-apiserver.yaml
        owner: root
        mode: 0644
    
  • envoy.yml

    - name: Envoy lb | 生成 envoy lb 配置文件
    template:
      src: envoy/envoy.conf.yaml.j2
      dest: /etc/kubernetes/plugins/lb-config/envoy.yaml
      owner: root
      mode: 0644
    register: lb_configuration_result
    
    - name: Envoy lb | 拉取相关镜像
      shell: "{{ image_pull_command }} {{ item }}"
      with_items:
      - "{{ lb_envoy_image }}"
      - "{{ pod_infra_container_image }}"
    
    - name: Envoy lb | 生成 envoy lb static pod 文件
      template:
        src: envoy/envoy.yaml.j2
        dest: /etc/kubernetes/manifests/lb-kube-apiserver.yaml
        owner: root
        mode: 0644
    
  • 当前节点在lb分组下主机中时,将会拉取keepalived镜像并设置

chrony
  • kubernetes需要集群中的节点时间必须一致,可以使用chrony从网络同步时间
etcd
  • etcd是一致且高可用的键值存储,用于kubernetes所有集群的后台数据库。具体介绍见https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/configure-upgrade-etcd/

    • 运行的 etcd 集群个数成员为奇数

    • etcd 是一个 leader-based 分布式系统。确保主节点定期向所有从节点发送心跳,以保持集群稳定

    • 确保不发生资源不足。集群的性能和稳定性对网络和磁盘 I/O 非常敏感,任何资源匮乏都会导致心跳超时, 从而导致集群的不稳定。不稳定的情况表明没有选出任何主节点。 在这种情况下,集群不能对其当前状态进行任何更改,这意味着不能调度新的 Pod

    • 保持 etcd 集群的稳定对 Kubernetes 集群的稳定性至关重要。 因此,请在专用机器或隔离环境上运行 etcd 集群

    • 在生产中运行的 etcd 的最低推荐版本是 3.2.10+

    • 使用有限的资源运行 etcd 只适合测试目的。为了在生产中部署,需要先进的硬件配置

etcd/certificates

查看main.yml了解整个流程

- name: 在 etcd 节点创建 etcd 相关目录
  file: 
    name: /etc/kubernetes/pki/etcd
    state: directory
  when: inventory_hostname in (groups['etcd'] + groups['new-etcd'])

- name: 在 master 节点创建 etcd 证书相关目录
  file: 
    name: /etc/kubernetes/pki/etcd
    state: directory
  when: inventory_hostname in (groups['kube-master'] + groups['new-master'])

- block:
  # 获取密钥状态
  - include_tasks: certs_stat.yml
  # 生成证书
  - include_tasks: generate.yml
  when: inventory_hostname == groups['etcd'][0]

# 分发证书
- include_tasks: distribute.yml
  • etcd、new-etcd分组下主机将创建/etc/kubernetes/pki/etcd目录

  • kube-master、new-master分组下主机将创建etcd正式相关目录

  • 在etcd组中第一个主机生成证书密钥

    • certs_stat.yml:查看etcd相关证书状况,并注册成变量

    • generate.yml:判断上一步注册的证书状况。如果证书已经存在则不做处理,如果不存在则创建证书

  • distribute.yml

    # 分发证书
    - name: 获取 etcd 相关证书
      slurp:
        src: /etc/kubernetes/pki/etcd/{{ item }}
      with_items:
      - ca.crt
      - ca.key
      - healthcheck-client.crt
      - healthcheck-client.key
      - peer.crt
      - peer.key
      - server.crt
      - server.key
      register: etcd_certs
      delegate_to: "{{ groups['etcd'][0] }}"
      run_once: true
    
    - name: 分发 etcd 相关证书到 etcd 节点
      copy:
        dest: "{{ item.source }}"
        content: "{{ item.content | b64decode }}"
        owner: root
        group: root
        mode: 0644
      no_log: true
      with_items: "{{ etcd_certs.results }}"
      when:
      - inventory_hostname != groups['etcd'][0]
      - inventory_hostname in (groups['etcd'] + groups['new-etcd'])
    
    - name: 获取 apiserver etcd client 证书
      slurp:
        src: /etc/kubernetes/pki/{{ item }}
      with_items:
      - etcd/ca.crt
      - apiserver-etcd-client.crt
      - apiserver-etcd-client.key
      register: etcd_client_certs
      delegate_to: "{{ groups['etcd'][0] }}"
      run_once: true
    
    - name: 分发 apiserver etcd client 证书到 master 节点
      copy:
        dest: "{{ item.source }}"
        content: "{{ item.content | b64decode }}"
        owner: root
        group: root
        mode: 0644
      no_log: true
      with_items: "{{ etcd_client_certs.results }}"
      when:
      - inventory_hostname != groups['etcd'][0]
      - inventory_hostname in (groups['kube-master'] + groups['new-master'])
    
    • slurp模块配置从src指定文件路径拉取文件;delegate_to配置需要执行拉取的文件的主机,这里设置的是etcd分组的第一个组件,也就是创建各种证书的主机,并通过register将拉取的所有文件放入etcd_certs变量中

    • 将etcd_certs变量中的个证书复制到除etcd分组第一个节点之外的其它etcd分组节点上

    • 从etcd分组的第一个节点获取apiserver etcd client 证书,放入etcd_client_certs变量

    • 分发 apiserver etcd client 证书到 master 节点

etcd/install

查看main.yml,了解etcd安装流程

- name: 判断 Docker 是否早已安装
  shell: >
    systemctl status docker | grep running || echo "not running"
  register: docker_already_running

- name: 设置 container_manager_detected 变量
  set_fact:
    container_manager_detected: >-
      {%- if "active" in docker_already_running.stdout -%}
      docker
      {%- else -%}
      containerd
      {%- endif -%}

- name: 创建 kubelet 相关目录
  file: 
    name: "{{ item }}"
    state: directory
  with_items:
  - "{{ kubelet_root_dir }}"
  - /etc/systemd/system/kubelet.service.d

- block:
  - name: 在 etcd 节点创建 etcd 相关目录
    file: 
      name: "{{ item }}"
      state: directory
      owner: root
      group: root
      mode: 0700
    with_items:
    - "{{ etcd_data_dir }}"
    - /etc/kubernetes/backup/etcd
    - /etc/kubernetes/pki/etcd
    - /etc/kubernetes/manifests

  - name: 在 etcd 节点拉取相关镜像
    shell: "{{ image_pull_command }} {{ item }}"
    with_items:
    - "{{ etcd_image }}"
    - "{{ pod_infra_container_image }}"

  - name: 读取 etcd static pod yaml 文件 stat 信息
    stat: 
      path: /etc/kubernetes/manifests/etcd-external.yaml
    register: etcd_static_pod_stat

  - name: 生成 etcd static pod 文件
    template: 
      src: etcd-external.yaml.j2
      dest: /etc/kubernetes/manifests/etcd-external.yaml
      owner: root
      mode: 0644
    # when: not etcd_static_pod_stat.stat.exists
  when: inventory_hostname in (groups['etcd'] + groups['new-etcd'])

- name: 读取 kubelet.conf 文件 stat 信息
  stat: 
    path: /etc/kubernetes/kubelet.conf
  register: kubelet_conf_stat

- block:
  - name: 获取 Docker Cgroup Driver 值
    shell: docker info --format '{{ '{{' }} json .CgroupDriver {{ '}}' }}' | cut -d'"' -f2
    register: docker_cgroup_driver
    when: container_manager_detected == 'docker'

  - name: 设置 docker 为容器运行时 kubelet_cgroup_driver_detected 变量
    set_fact:
      kubelet_cgroup_driver_detected: >-
        {{ docker_cgroup_driver.stdout }}
    when: container_manager_detected == 'docker'

  - name: 设置 containerd 为容器运行时 kubelet_cgroup_driver_detected 变量
    set_fact:
      kubelet_cgroup_driver_detected: >-
        {%- if containerd_use_systemd_cgroup -%}systemd{%- else -%}cgroupfs{%- endif -%}
    when: container_manager_detected == 'containerd'

  - name: 生成临时 kubelet unit 文件
    template: 
      src: 20-kubelet-override.conf.j2
      dest: /etc/systemd/system/kubelet.service.d/20-kubelet-override.conf
      owner: root
      mode: 0644

  - name: 重新加载 daemon
    systemd:
      daemon_reload: yes

  - name: 临时启动 kubelet 以引导 etcd 运行
    service:
      name: kubelet
      state: restarted
      enabled: yes

  when: 
  - inventory_hostname in (groups['etcd'] + groups['new-etcd'])
  - not kubelet_conf_stat.stat.exists

- include_tasks: docker.yml
  when: container_manager_detected == 'docker'

- include_tasks: containerd.yml
  when: container_manager_detected == 'containerd'

- block:
  - name: 移除临时 kubelet unit 文件
    file: 
      name: /etc/systemd/system/kubelet.service.d/20-kubelet-override.conf
      state: absent

  - name: 重新加载 daemon
    systemd:
      daemon_reload: yes
  - name: 停止临时启动 kubelet
    service:
      name: kubelet
      state: stopped
      enabled: yes
  when: 
  - inventory_hostname in (groups['kube-master'] + groups['kube-worker'] + groups['new-master'] + groups['new-worker']) 
  - not kubelet_conf_stat.stat.exists

- block:
  - name: 第一个 etcd 节点创建 etcd 备份工具
    template: 
      src: etcdtools.j2
      dest: /etc/kubernetes/backup/etcd/etcdtools
      owner: root
      mode: 0755
  - name: 第一个 etcd 节点创建 etcd 定时备份 crontab
    cron: 
      minute: "0"
      hour: "{{ etcd_backup_hour }}"
      name: Backup etcd databases
      job: >
        /etc/kubernetes/backup/etcd/etcdtools backup
  - name: 第一个 etcd 节点创建清理 etcd 定时备份文件 crontab
    cron: 
      minute: "30"
      hour: "{{ etcd_backup_hour }}"
      name: Clean etcd databases backup file
      job: >
        /etc/kubernetes/backup/etcd/etcdtools cleanup
  when: inventory_hostname == groups['etcd'][0]
  • 判断docker是否安装及判断安装容器管理类型

  • 创建kubelet_root_dir目录及kubelet服务文件

  • etcd、new-etcd分组下节点完成etcd_data_dir等目录创建、拉取etcd镜像及pause镜像、将etcd-external.yaml.j2文件内容复制到/etc/kubernetes/manifests/etcd-external.yaml

  • 如果/etc/kubernetes/kubelet.conf不存在,则对于容器管理器为docker,设置kubelet_cgroup_driver_detected;对于容器管理器为containerd,设置kubelet_cgroup_driver_detected两者获取方式不同、将20-kubelet-override.conf.j2复制到/etc/systemd/system/kubelet.service.d/20-kubelet-override.conf、重启daemon、重启kubelet

docker.yml
- name: 以轮询的方式等待 etcd 运行完成
  shell: >
    docker run --net host -e ETCDCTL_API=3 
    -v /etc/kubernetes/pki/etcd:/etc/kubernetes/pki/etcd
    --rm {{ etcd_image }}
    etcdctl endpoint health
    --endpoints=https://[127.0.0.1]:2379
    --cacert=/etc/kubernetes/pki/etcd/ca.crt
    --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
    --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt
  register: etcd_status
  until: etcd_status.rc == 0
  retries: 12
  delay: 5
  when: inventory_hostname in groups['etcd']

- name: 校验新添加的 etcd 节点是否已在 etcd 集群中
  shell: >
    docker run --net host -e ETCDCTL_API=3 
    -v /etc/kubernetes/pki/etcd:/etc/kubernetes/pki/etcd
    --rm {{ etcd_image }}
    etcdctl member list
    --endpoints=https://[127.0.0.1]:2379
    --cacert=/etc/kubernetes/pki/etcd/ca.crt
    --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
    --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt
  register: etcd_member_list
  delegate_to: "{{ groups['etcd'][0] }}"
  when: inventory_hostname in groups['new-etcd']

- name: 将新添加的 etcd 节点添加到 etcd 集群中
  shell: >
    docker run --net host -e ETCDCTL_API=3 
    -v /etc/kubernetes/pki/etcd:/etc/kubernetes/pki/etcd
    --rm {{ etcd_image }}
    etcdctl member add {{ etcd_new_member }}
    --endpoints=https://[127.0.0.1]:2379
    --cacert=/etc/kubernetes/pki/etcd/ca.crt
    --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
    --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt
  register: etcd_member_add
  until: etcd_member_add.rc == 0
  retries: 12
  delay: 5
  delegate_to: "{{ groups['etcd'][0] }}"
  when: 
  - inventory_hostname in groups['new-etcd']
  - inventory_hostname not in etcd_member_list.stdout

- name: 以轮询的方式等待 new etcd 运行完成
  shell: >
    docker run --net host -e ETCDCTL_API=3 
    -v /etc/kubernetes/pki/etcd:/etc/kubernetes/pki/etcd
    --rm {{ etcd_image }}
    etcdctl endpoint health
    --endpoints=https://[127.0.0.1]:2379
    --cacert=/etc/kubernetes/pki/etcd/ca.crt
    --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
    --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt
  register: etcd_status
  until: etcd_status.rc == 0
  retries: 12
  delay: 5
  when: inventory_hostname in groups['new-etcd']
  • 轮询的方式等待 etcd 运行完成

  • 校验新添加的 etcd 节点是否已在 etcd 集群中

  • 将新添加的 etcd 节点添加到 etcd 集群中

  • 以轮询的方式等待 new etcd 运行完成

containerd.yml

与docker类似,流程一样只是运行容器指令不同

- name: 以轮询的方式等待 etcd 运行完成
  shell: >
    ctr -n k8s.io run --net-host --env ETCDCTL_API=3
    --mount type=bind,src=/etc/kubernetes/pki/etcd,dst=/etc/kubernetes/pki/etcd,options=rbind:ro
    --rm {{ etcd_image }} etcd-health-check
    etcdctl endpoint health
    --endpoints=https://[127.0.0.1]:2379
    --cacert=/etc/kubernetes/pki/etcd/ca.crt
    --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
    --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt
  register: etcd_status
  until: etcd_status.rc == 0
  retries: 12
  delay: 5
  when: inventory_hostname in groups['etcd']

- name: 校验新添加的 etcd 节点是否已在 etcd 集群中
  shell: >
    ctr -n k8s.io run --net-host --env ETCDCTL_API=3
    --mount type=bind,src=/etc/kubernetes/pki/etcd,dst=/etc/kubernetes/pki/etcd,options=rbind:ro
    --rm {{ etcd_image }} etcd-list-member
    etcdctl member list
    --endpoints=https://[127.0.0.1]:2379
    --cacert=/etc/kubernetes/pki/etcd/ca.crt
    --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
    --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt
  register: etcd_member_list
  delegate_to: "{{ groups['etcd'][0] }}"
  when: inventory_hostname in groups['new-etcd']

- name: 将新添加的 etcd 节点添加到 etcd 集群中
  shell: >
    ctr -n k8s.io run --net-host --env ETCDCTL_API=3
    --mount type=bind,src=/etc/kubernetes/pki/etcd,dst=/etc/kubernetes/pki/etcd,options=rbind:ro
    --rm {{ etcd_image }} etcd-add-member
    etcdctl member add {{ etcd_new_member }}
    --endpoints=https://[127.0.0.1]:2379
    --cacert=/etc/kubernetes/pki/etcd/ca.crt
    --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
    --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt
  register: etcd_member_add
  until: etcd_member_add.rc == 0
  retries: 12
  delay: 5
  delegate_to: "{{ groups['etcd'][0] }}"
  when: 
  - inventory_hostname in groups['new-etcd']
  - inventory_hostname not in etcd_member_list.stdout

- name: 以轮询的方式等待 new etcd 运行完成
  shell: >
    ctr -n k8s.io run --net-host --env ETCDCTL_API=3
    --mount type=bind,src=/etc/kubernetes/pki/etcd,dst=/etc/kubernetes/pki/etcd,options=rbind:ro
    --rm {{ etcd_image }} etcd-health-check
    etcdctl endpoint health
    --endpoints=https://[127.0.0.1]:2379
    --cacert=/etc/kubernetes/pki/etcd/ca.crt
    --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
    --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt
  register: etcd_status
  until: etcd_status.rc == 0
  retries: 12
  delay: 5
  when: inventory_hostname in groups['new-etcd']
生成 kubernetes 所需证书

查看main.yml了解生成证书流程

- name: 创建 kubernetes 证书存放目录
  file: 
    name: "{{ item }}"
    state: directory
  with_items:
  - /etc/kubernetes/pki
  - /var/lib/kubelet/pki
  when: 
  - inventory_hostname in (groups['kube-master'] + groups['new-master'] + groups['kube-worker'] + groups['new-worker'])

- block:
  # 获取密钥状态
  - include_tasks: certs_stat.yml
  # 生成公共证书
  - include_tasks: common.yml
  when: inventory_hostname == groups['kube-master'][0]

# 分发证书
- include_tasks: distribute.yml
  when: 
  - inventory_hostname in (groups['kube-master'] + groups['new-master'] + groups['kube-worker'] + groups['new-worker'])

- name: 读取 kubelet.conf 文件 stat 信息
  stat: 
    path: /etc/kubernetes/kubelet.conf
  register: kubelet_conf_stat
  when: 
  - inventory_hostname in (groups['kube-master'] + groups['new-master'] + groups['kube-worker'] + groups['new-worker'])

- include_tasks: kubeconfig.yml
  when: 
  - kubelet_conf_stat.stat.exists
  - inventory_hostname in (groups['kube-master'] + groups['new-master'] + groups['kube-worker'] + groups['new-worker'])
  • 创建 kubernetes 证书存放目录

  • 检查kube-master分组第一个节点下,证书的状态,如果证书没有被创建,则创建证书

  • 将证书分发到其它节点

  • 创建admin.conf 配置文件

  • 创建 scheduler.conf 配置文件

  • 创建 controller-manager.conf 配置文件

  • 创建{{ ansible_env.PWD }}/.kube、{{ansible_env.HOME}}/.kube目录

  • 将/etc/kubernetes/admin.conf文件内容输出输出到{{ ansible_env.PWD | default(‘/root’) }}/.kube、{{ansible_env.HOME | default(‘/root’) }}/.kube目录下config文件中

  • 设置config文件权限

  • 刷新节点kubelet-client证书

  • 刷新节点kubelet.conf 配置的证书

初始化master节点
- name: 判断 Docker 是否早已安装
  shell: >
    systemctl status docker | grep running || echo "not running"
  register: docker_already_running

- name: 设置 container_manager_detected 变量
  set_fact:
    container_manager_detected: >-
      {%- if "active" in docker_already_running.stdout -%}
      docker
      {%- else -%}
      containerd
      {%- endif -%}

- name: 创建 kubernetes 相关目录
  file: 
    name: "{{ item }}"
    state: directory
  with_items:
  - "{{ kubelet_root_dir }}"
  - "{{ audit_policy_file | dirname }}"
  - /etc/kubernetes/pki
  - /etc/kubernetes/config
  - /etc/kubernetes/manifests
  - /var/log/kubernetes/audit
  - /usr/share/bash-completion/completions

- name: 读取 kubelet.conf 文件 stat 信息
  stat: 
    path: /etc/kubernetes/kubelet.conf
  register: kubelet_conf_stat

# 生成 kubeadm 配置
- include_tasks: kubeadm-config.yml

- name: 创建 EncryptionConfiguration 配置文件
  template:
    src: secrets-encryption.yaml.j2
    dest: /etc/kubernetes/pki/secrets-encryption.yaml
    owner: root
    group: root
    mode: 0644

- name: 创建 apiserver 审计日志策略配置文件
  template:
    src: apiserver-audit-policy.yaml.j2
    dest: "{{ audit_policy_file }}"
    owner: root
    group: root
    mode: 0644
  when: kubernetes_audit|default(false)

# 初始化第一个 master 节点
- include_tasks: master-init.yml
  when: 
  - not kubelet_conf_stat.stat.exists
  - inventory_hostname == groups['kube-master'][0]

# 初始化其他 master 节点
- include_tasks: master-join.yml
  when: 
  - not kubelet_conf_stat.stat.exists
  - inventory_hostname != groups['kube-master'][0]
  - inventory_hostname in (groups['kube-master'] + groups['new-master'])

- name: 确认 kubelet 配置是否有修改
  template:
    src: kubelet-config.v1beta1.yaml.j2
    dest: /var/lib/kubelet/config.yaml
    owner: root
    mode: 0644
  register: configuration_result

- name: 启动/重启 kubelet
  service:
    name: kubelet
    state: restarted
    enabled: yes
  when: configuration_result.changed
  • 创建kubernetes 相关目录

  • 读取kubelet.conf 文件 stat 信息

  • 生成 kubeadm 配置

    - name: 确认 kubeadm 版本
    command: "kubeadm version -o short"
    register: kubeadm_version_output
    
    - name: 设置 kubeadm api version 为 v1beta1
      set_fact:
        kubeadmConfig_api_version: v1beta1
      when:
      - kubeadm_version_output.stdout is version('v1.13.0', '>=')
      - kubeadm_version_output.stdout is version('v1.15.0', '<')
    
    - name: 设置 kubeadm api version 为 v1beta2
      set_fact:
        kubeadmConfig_api_version: v1beta2
      when:
      - kubeadm_version_output.stdout is version('v1.15.0', '>=')
    
    - name: 获取 Docker Cgroup Driver 值
      shell: docker info --format '{{ '{{' }} json .CgroupDriver {{ '}}' }}' | cut -d'"' -f2
      register: docker_cgroup_driver
      when: container_manager_detected == 'docker'
    
    - name: 设置 docker 为容器运行时 kubelet_cgroup_driver_detected 变量
      set_fact:
        kubelet_cgroup_driver_detected: >-
          {{ docker_cgroup_driver.stdout }}
      when: container_manager_detected == 'docker'
    
    - name: 设置 containerd 为容器运行时 kubelet_cgroup_driver_detected 变量
      set_fact:
        kubelet_cgroup_driver_detected: >-
          {%- if containerd_use_systemd_cgroup -%}systemd{%- else -%}cgroupfs{%- endif -%}
      when: container_manager_detected == 'containerd'
    
    - name: 创建 kubeadm 的配置文件
      template:
        src: >-
          {% if inventory_hostname == groups['kube-master'][0] -%}
          kubeadm-controlplane-init.{{ kubeadmConfig_api_version }}.yaml.j2
          {%- elif inventory_hostname in (groups['kube-master'] + groups['new-master']) -%}
          kubeadm-controlplane-join.{{ kubeadmConfig_api_version }}.yaml.j2
          {%- else -%}
          kubeadm-join.{{ kubeadmConfig_api_version }}.yaml.j2
          {%- endif %}
        dest: "/etc/kubernetes/kubeadm-config.yaml"
        owner: root
        mode: 0644
    
    • 通过命令kubeadm version -o short查看kubeadm 版本,根据版本确定kubeadmConfig_api_version版本

    • 根据不同容器管理器,设置docker_cgroup_driver变量值

    • 根据不同的节点分组,使用不同的模版设置/etc/kubernetes/kubeadm-config.yaml文件

    • 使用secrets-encryption.yaml.j2模版内容填充/etc/kubernetes/pki/secrets-encryption.yaml文件,EncryptionConfig类型资源用于指定需要加密的资源,详情查看https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/encrypt-data/

      kind: EncryptionConfig
      apiVersion: v1
      resources:
        - resources:
          - secrets
          providers:
          - aescbc:
            keys:
            - name: key
              secret: GPG4RC0Vyk7+Mz/niQPttxLIeL4HF96oRCcBRyKNpfM=
          - identity: {}
    
  • 配置审计策略配置文件,默认不配置。审计策略配置文件可以控制K8s中记录各种活动的行为,详情请看https://kubernetes.io/zh-cn/docs/tasks/debug/debug-cluster/audit/

  • 初始化第一个master节点

  • 初始化其它master节点。与初始化第一个master节点类似,不同之处在于

    • 加入一个新的节点需要使用kubeadm join,该指令详细讲解请看https://kubernetes.io/zh-cn/docs/reference/setup-tools/kubeadm/kubeadm-join/

    • 不需要再 授权 kubelet 自动轮换服务端证书、配置 Pod 安全策略

  • 如果kubelet 配置有修改则会执行重启kubelet

使用模版设置/etc/kubernetes/kubeadm-config.yaml文件解析

kubeadm-config.yaml配置文件用于kubeadm init初始化控制平面节点或者kubeadm join将工作节点加入集群。根据执行的不同指令(init或join)对于配置文件中的配置类型有不同的需求

当执行kubeadm init命令时,可以使用下面的配置类型。但InitConfiguration和ClusterConfiguration之间只有一个是必须提供

  • InitConfiguration

  • ClusterConfiguration

  • KubeProxyConfiguration

  • kubeletConfiguration

当执行kubeadm join时,需要提供JoinConfiguration类型配置

####### InitConfiguration字段解析
InitConfiguration 包含一组特定于 “kubeadm init” 的运行时元素。 这里的字段仅用于第一次运行 kubeadm init 命令。 之后,此结构中的字段信息不会再被上传到 kubeadm upgrade 所要使用的 kubeadm-config ConfigMap 中

  • localAPIEndpoint:控制平面节点上要部署的API服务器的端点

    • advertiseAddress:设置 API 服务器要公布的 IP 地址

    • bindPort:设置 API 服务器要绑定到的安全端口。默认值为 6443

  • nodeRegistration:包含向集群中注册新控制平面节点相关的字段

    • kubeletExtraArgs:用于向kubelet传递额外参数

    • criSocket:用于读取容器运行时信息,此信息会以注解方式添加到Node API对象上,用于后续用途

    • name:Node API对象的.metadata.name字段值

  • bootstrapTokens:在kubeadm init执行时会被用到,其中描述了一组要创建的启动引导令牌,这里的信息不会被上传到 kubeadm 在集群中保存的 ConfigMap 中,部分原因是由于信息 本身比较敏感

    • groups:设定此令牌被用于身份认证时对应的附加用户组

    • token:token 用来在节点与控制面之间建立双向的信任关系。 在向集群中添加节点时使用

    • ttl:定义此令牌的声明周期。默认为 24h

    • usages:描述此令牌的可能使用方式。默认情况下,令牌可用于 建立双向的信任关系;不过这里可以改变默认用途

####### ClusterConfiguration字段解析
用于定制集群范围的设置

  • networking:包含集群网络拓扑配置,可以定制pod的子网络或者service的子网络

    • dnsDomain:Kubernetes服务所使用的DNS域名,默认值为"cluster.local"

    • podSubnet:pod所使用的子网

    • serviceSubnet:Kubernetes service所使用的子网,默认值为"10.96.0.0/12"

  • etcd:etcd数据库配置,可以定制本地etcd或配置API服务器使用一个外部etcd集群

    • local:提供配置本地etcd实例选项,与external互斥

      • ImageMeta:允许用户为etcd定制要使用的容器

        • imageRepository:设置镜像拉取所用的容器仓库。若未设置,则使用ClusterConfiguration中的imageRepository

        • imageTag:允许用户设置镜像的标签,如果设置此字段,则kubeadm不再在集群升级时自动更改组件的版本

      • dataDir:etcd用来存放数据的目录,默认为"/var/lib/etcd"

      • extraArgs:为etcd可执行文件提供的额外参数,用于在静态Pod中运行etcd,映射中的每个键对应命令行上的一个标志参数,只是去掉了前面的参数连字符

      • serverCertSANs:为etcd服务器的签名证书设置额外的主体替代名

      • peerCertSANs:为etcd的对等端签名证书设置额外的主体替代名

    • external:描述如何连接到外部的etcd集群,与local互斥

      • endpoints:包含一组etcd成员列表

      • caFile:SSL证书机构(CA)文件,用来加密etcd通信,如果使用TLS连接,此字段为必需字段

      • certFile:SSL证书文件,用于加密etcd通信,使用TLS连接,此字段为必需

      • keyFile:SSL密钥文件,用于加密etcd通信,使用TLS连接,此字段必需

  • apiServer:包含API服务器的一些额外配置

    • extraArgs:要传递给控制平面组件的一组额外参数,映射中的每个键对应命令行上使用的标准名称

    • extraVolumes:一组额外的主机卷,需要挂载到控制平面组件中

    • certSANs:设置API服务器签署证书所用的额外主题替代名

    • timeoutForControlPla:用来控制等待API服务器开始运行的超时时间

  • controllerManager:包含控制器管理器的额外配置

    • extraArgs:要传递给控制平面组件的一组额外参数,映射中的每个键对应命令行上使用的标准名称

    • extraVolumes:一组额外的主机卷,需要挂载到控制平面组件中

  • scheduler:包含调度器的额外配置

    • extraArgs:要传递给控制平面组件的一组额外参数,映射中的每个键对应命令行上使用的标准名称

    • extraVolumes:一组额外的主机卷,需要挂载到控制平面组件中

####### KubeletConfiguration字段解析
用来更改传递给在集群中部署的kubelet实例的配置

  • address:kubelet提供服务所用的IP地址

  • authentication:设置发送给kubelet服务器的请求是如何进行身份认证的

    • anonymous:包含与匿名身份认证相关的配置信息

      • enabled:允许匿名用户向kubelet服务器发送请求。未被其他身份认证方法拒绝的请求都会被当做匿名请求。匿名请求对应的用户名为system:anonymous,对应的用户组名为system:unauthenticated
    • webhook:包含与Webhook持有者令牌认证相关的配置

      • enabled:允许使用tokenreviews.authentication.k8s.io API来提供持有者令牌身份认证

      • cacheTTL:启用对身份认证结果的缓存,设置时间

      • x509:包含与x509客户端证书认证相关的配置

  • authorization:设置发送给kubelet服务器的请求是如何进行鉴权的

    • webhook:包含与Webhook鉴权相关的配置信息

      • cacheAuthorizedTTL:设置来自Webhook鉴权组件的"authorized"响应的缓存时常

      • cacheUnauthorizedTTL:设置来自Webhook鉴权组件的"unauthorized"响应的缓存时常

  • cgroupDriver:是kubelet用来操控宿主系统上控制组的驱动程序

  • cgroupsPerQOS:启用基于QoS的控制组层次结构:顶层的控制组用于不同QoS类,所有Burstable和BestEffort pod都会被放置到对应的顶级QoS控制组下

  • clusterDNS:集群DNS服务器的IP地址的列表。如果设置了,kubelet将会配置所有容器使用这里的IP地址而不是宿主系统上的DNS服务器来完成DNS解析

  • clusterDomain:集群DNS域名。如果设置此字段,kubelet会配置所有容器,使之在搜索主机的搜索域的同时也搜索这里的DNS域

  • configMapAndSecretChangeDetectionStrategy:ConfigMap和Secret管理器的运行模式。合法值如下:

    • Get:kubelet直接从API服务器取回必要的对象

    • Cache:kubelet使用TTL缓存来管理来自API服务器的对象

    • Watch:kubelet使用watch操作来观察所关心的对象变更

  • containerLogMaxFiles:设置每个容器可以存在的日志文件个数上限

  • containerLogMaxSize:定义容器日志文件被轮转之前可以达到的最大尺寸

  • contentType:API服务器发送请求时使用的内容类型

  • cpuCFSQuota:允许为设置了CPU限制的容器实施CPU CFS配额约束

  • cpuCFSQuotaPeriod:设置CPU CFS配额周期值,cpu.cfs_period_us。此值需要介于1毫秒和1秒之间,包含1毫秒和1秒。此功能要求启用 CustomCPUCFSQuotaPeriod

  • cpuManagerPolicy:要使用的策略名称。需要启用CPUManger

  • cpuManagerReconcilePeriod:CPU管理器的协调周期时长。需要启用CPUManager

  • enableControllerAttachDetach:允许Attach/Detach控制器管理调度到节点的卷的挂接和解除挂接,并且禁止kubelet执行任何attach/detach操作

  • evictionHard:维护硬性驱逐域值映射。如果需要禁用,可显式在对应资源上设置其阈值为0%或100%。更多信息请看https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/node-pressure-eviction/

  • kubeReserved:描述为Kubernetes系统组件预留的资源。支持CPU、内存和根文件系统的本地存储,例如cpu: 100m,memory: 256M

  • evictionPressureTransitionPeriod:kubelet离开驱逐压力状况之前必须等待的时长

  • fileCheckFrequency:设置对配置文件中新数据进行检查的时间间隔,设置为0s将不会检查这些文件,将导致容器状态不可预测或延迟

  • hairpinMode:设置kubelet如何为发夹模式数据包配置容器网桥,设置此字段可以让Service中的端点尝试访问自身Service时将服务请求路由到自身。可选值如下

    • promiscuous-bridge:将容器网桥设置为混杂模式

    • hairpin-veth:在容器的veth接口上设置发夹模式

    • none:什么都不做

  • maxOpenFiles:kubelet进程可以打开的文件个数,此值不能为负数

  • maxPods:kubelet上可运行pod个数上限,不能为负数

  • nodeLeaseDuration:设置此参数会同步设置Lease资源对象的leaseDurationSeconds属性,Lease资源被创建在kube-node-lease命名空间下。如果在此参数值设置的周期内节点没有续约,则认为此节点不健康

  • port:kubelet用来提供服务所使用的端口,此端口必需介于1~65535,默认值10250

  • resolvConf:指定域名解析配置文件,用作容器DNS解析配置的基础。如果此值设置为空字符串,则相当于禁用了DNS查询,默认值/etc/resolv.conf

  • staticPodPath:指向要运行的本地pod目录,或者指向某个静态pod文件的路径

####### KubeProxyConfiguration字段解析
用于配置Kubernetes代理服务器,主要字段解析如下

  • bindAddress:代理服务器提供服务所用的IP地址,设置为0.0.0.0则在所有网络接口上提供服务

  • clientConnection:设置代理服务器与API服务器通信时要使用的kubeconfig文件和客户端链接设置

    • kubeconfig:指向一个KubeConfig文件路径
  • clusterCIDR:集群中pod所使用的CIDR范围,此地址范围用于对来自集群外请求流量进行桥接。如果未设置,则kube-proxy不会对非集群内部的流量做桥接

  • conntrack:

    • maxPerCore:每个CPU核所跟踪的NAT链接的个数上限

    • tcpEstablishedTimeout:空闲TCP连接的保留时间

    • tcpCloseWaitTimeout:设置空闲的CLOSE_WAIT状态的conntrack条目保留在conntrack列表的时间

  • mode:设置使用的代理模式,如果未设置则使用最佳代理模式,liunx默认使用iptables

    • liunx平台支持:iptables、ipvs

    • windows平台支持:kernelspace

初始化第一个master节点
- name: 确认 kubelet 已停止运行
  service:
    name: kubelet
    state: stopped
    enabled: yes

- name: 获取 master 节点需要拉取的镜像列表
  shell: >
    kubeadm config images list --config=/etc/kubernetes/kubeadm-config.yaml | grep -v coredns | 
    grep {{ kube_image_repository }}
  register: kube_image_list

- name: 开始拉取 master 节点相关镜像
  shell: "{{ image_pull_command }} {{ item }}"
  with_items: "{{ kube_image_list.stdout_lines }}"

- name: 初始化第一个 master 节点
  shell: kubeadm init --config=/etc/kubernetes/kubeadm-config.yaml --ignore-preflight-errors=ImagePull

- include_tasks: "{{ (role_path + '/../kube-certificates/tasks/kubeconfig.yml') | realpath  }}"

- name: 重新加载 daemon
  systemd:
    daemon_reload: yes

- name: 重新启动 kubelet
  service:
    name: kubelet
    state: restarted
    enabled: yes

- name: 等待 apiserver 运行
  uri:
    url: "https://{{ current_host_ip }}:6443/healthz"
    validate_certs: no
  register: apiserver_result
  until: apiserver_result.status == 200
  retries: 60
  delay: 5

- name: 等待 kube-scheduler 运行
  uri:
    url: "https://127.0.0.1:10259/healthz"
    validate_certs: no
  register: scheduler_result
  until: scheduler_result.status == 200
  retries: 60
  delay: 5

- name: 等待 kube-controller-manager 运行
  uri:
    url: "https://127.0.0.1:10257/healthz"
    validate_certs: no
  register: controller_manager_result
  until: controller_manager_result.status == 200
  retries: 60
  delay: 5

- name: 创建 kubelet 自动轮换服务端证书配置
  template:
    src: kubelet-certificates-renewal.yaml.j2
    dest: /etc/kubernetes/config/kubelet-certificates-renewal.yaml
    owner: root
    group: root
    mode: 0644

- name: 授权 kubelet 自动轮换服务端证书
  shell: kubectl apply -f /etc/kubernetes/config/kubelet-certificates-renewal.yaml

- block:
  - name: 创建 Pod 安全策略配置文件
    template:
      src: pod-security-policy.yaml.j2
      dest: /etc/kubernetes/config/pod-security-policy.yaml
      owner: root
      group: root
      mode: 0644
  
  - name: 配置 Pod 安全策略
    shell: kubectl apply -f /etc/kubernetes/config/pod-security-policy.yaml
  when: '"PodSecurityPolicy" in kube_apiserver_enable_admission_plugins'
  • 获取需要拉取的镜像列表
    在这里插入图片描述

  • 拉取镜像列表镜像

  • 使用init命令初始化第一个master节点,忽略拉取镜像错误。指令详情请看https://kubernetes.io/zh-cn/docs/reference/setup-tools/kubeadm/kubeadm-init/

  • 设置pod安全策略。详情请看https://kubernetes.io/zh-cn/docs/concepts/security/pod-security-policy/

初始化worker节点
- name: 判断 Docker 是否早已安装
  shell: >
    systemctl status docker | grep running || echo "not running"
  register: docker_already_running

- name: 设置 container_manager_detected 变量
  set_fact:
    container_manager_detected: >-
      {%- if "active" in docker_already_running.stdout -%}
      docker
      {%- else -%}
      containerd
      {%- endif -%}

- name: 创建 kubernetes 相关目录
  file: 
    name: "{{ item }}"
    state: directory
  with_items:
  - "{{ kubelet_root_dir }}"
  - /etc/kubernetes
  - /usr/share/bash-completion/completions

- name: 读取 kubelet.conf 文件 stat 信息
  stat:
    path: /etc/kubernetes/kubelet.conf
  register: kubelet_conf_stat

- include_tasks: "{{ (role_path + '/../kube-master/tasks/kubeadm-config.yml') | realpath  }}"
  when: 
  - inventory_hostname in (groups['kube-worker'] + groups['new-worker'])
  - inventory_hostname not in (groups['kube-master'] + groups['new-master'])

- block:
  - name: 确认 kubelet 已停止运行
    service:
      name: kubelet
      state: stopped
      enabled: yes

  - name: Worker 节点加入集群
    shell: >
      kubeadm join --config /etc/kubernetes/kubeadm-config.yaml 
      --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests,FileAvailable--etc-kubernetes-pki-ca.crt

  when: 
  - inventory_hostname in (groups['kube-worker'] + groups['new-worker'])
  - inventory_hostname not in (groups['kube-master'] + groups['new-master'])
  - not kubelet_conf_stat.stat.exists

- block:
  - name: 确认 kubelet 配置是否有修改
    template:
      src: kubelet-config.v1beta1.yaml.j2
      dest: /var/lib/kubelet/config.yaml
      owner: root
      mode: 0644
    register: configuration_result
  
  - name: 启动/重启 kubelet
    service:
      name: kubelet
      state: restarted
      enabled: yes
    when: configuration_result.changed
  when: 
  - inventory_hostname in (groups['kube-worker'] + groups['new-worker'])
  - inventory_hostname not in (groups['kube-master'] + groups['new-master'])

# - name: 取消在 worker 组的 master 节点 taint,使 master 节点可以调度
#   shell: >
#     kubectl taint nodes {{inventory_hostname}} node-role.kubernetes.io/control-plane='':NoSchedule --overwrite &&
#     kubectl taint nodes {{inventory_hostname}} node-role.kubernetes.io/control-plane-
#   delegate_to: "{{ groups['kube-master'][0] }}"
#   ignore_errors: yes
#   when: 
#   - inventory_hostname in (groups['kube-worker'] + groups['new-worker'])
#   - inventory_hostname in (groups['kube-master'] + groups['new-master']) 
  • 使用kubeadm join添加工作节点

  • 如果/var/lib/kubelet/config.yaml配置有变更则重启kubelet

标记节点角色
- name: 获取当前集群节点信息
  shell: kubectl get node -o name
  delegate_to: "{{ groups['kube-master'][0] }}"
  ignore_errors: true
  run_once: true
  register: kubectl_get_node_output

- block:
  - name: 取消节点原有角色标签
    shell: >
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/control-plane- &&
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/master- &&
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/worker- &&
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/lb- &&
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/etcd-

  - name: 设置控制面节点 role
    shell: >
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/control-plane='' --overwrite &&
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/master='' --overwrite 
    when: inventory_hostname in (groups['kube-master'] + groups['new-master']) 

  - name: 设置 worker 节点 role
    shell: >
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/worker='' --overwrite
    when: inventory_hostname in (groups['kube-worker'] + groups['new-worker']) 

  - name: 设置 load balancer 节点 role
    shell: >
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/lb='' --overwrite
    when: inventory_hostname in groups['lb']

  - name: 设置 etcd 节点 role
    shell: >
      kubectl label node {{ inventory_hostname }} node-role.kubernetes.io/etcd='' --overwrite
    when: inventory_hostname in (groups['etcd'] + groups['new-etcd'])

  ignore_errors: true
  delegate_to: "{{ groups['kube-master'][0] }}"
  when: inventory_hostname in kubectl_get_node_output.stdout
  • delegate_to委派在master节点组中第一个节点执行查询K8s集群节点名列表,并注册在kubectl_get_node_output变量中,供后面使用

  • 如果节点在K8s集群列表中,则设置节点角色,设置节点角色操作也是在master节点组中第一个节点执行

    • 通过覆盖角色标签的方式取消节点的标签

    • 如果节点在master分组下,则设置控制平面角色和master节点角色

    • 如果节点在worker分组下,则设置工作节点角色

    • 如果节点是lb节点,则设置lb角色

    • 如果节点在etcd组下,则设置etcd角色

安装插件

在第一个主节点上执行安装各种插件

  • 安装网络插件

  • 安装ingress-controller,用于通过ingress类型资源暴露service

  • 安装系统指标插件,收集各组件指标

  • 安装K8s仪表盘

  • 安装证书管理插件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/508195.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二叉树原理

二叉树原理TOC 二叉树是公认的难解型数据结构&#xff0c;这里试着系统化的讨论一些与二叉树有关的内容&#xff1a; 二叉树的数据标记方法&#xff1a;层次数据&#xff08;int t[N];&#xff09;,左右树标记&#xff08;bool lr:0standForL, 1standForR&#xff09;&#xf…

算法之路--冒泡排序算法

写在前面 很早就想系统梳理所接触的所有算法&#xff0c;但是只是存在于一个想法阶段&#xff0c;懒惰使人遗忘不是么。作为一个软件开发人员&#xff0c;绕不开算法与数据结构&#xff0c;既然绕不开&#xff0c;何不逐一分析学习透彻&#xff0c;与君共勉之。 冒泡排序算法&a…

单片机c51中断 — 中断嵌套实例IE0的置位和撤销

项目文件 文件 关于项目的内容知识点可以见专栏单片机原理及应用 的第五章&#xff0c;中断 根据下原理图&#xff0c;编程验证二级外部中断嵌套效果。其中K0定为低优先级中断源&#xff0c;K1为高优先级中断源。此外&#xff0c;利用发光二极管D1验证外部中断请求标志IE0在脉…

Minio(minio-20221029062133.0.0.x86_64.rpm) Linux 环境安装

Minio Linux 环境安装 资源下载 镜像下载地址&#xff1a;http://dltest.minio.org.cn/server/minio/release/linux-amd64/archive/ 资源包下载地址&#xff08;与献文匹配&#xff09;&#xff1a;https://download.csdn.net/download/scdncby/87769604 安装 上传rpm安装…

React+Antd+Vite+TypeScript 项目实战教程

本教程属于react入门教程&#xff0c;课程围绕如何搭建一个项目框架展开&#xff0c;会带你快速了解react、redux、redux-devtool、react-router-dom、axiox这些常见技术的使用方式&#xff0c;教程最后会附上项目源码。 一、创建项目 在搭建项目时&#xff0c;我们通常会使用…

day38_JDBC

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、数据库连接池 二、反射 三、封装DBUtil 零、 复习昨日 SQL注入 预处理语句 String sql "select * from user where id ?"; PreparedStat…

Spring Boot访问数据库

SpringBoot访问数据库时&#xff0c;我们可以使用以下三种&#xff0c;JdbcTemplate、Spring Boot Data Jpa、mybatis。 JdbcTemplate是Spring自己提供的&#xff0c;但是其操作不方便&#xff0c;甚至有些繁琐&#xff0c;在实际应用中也是很少会使用&#xff0c;所以这里就不…

使用MobaXterm在Windows系统远程Ubuntu系统

使用场景 通常大部分办公软件都安装在Windows系统上&#xff0c;使用Windows系统办公更便捷&#xff0c;并且大多办公软件在Ubuntu系统上不兼容&#xff0c;即使进行处理&#xff0c;使用体验也不好&#xff0c;下面针对在同一局域网使用Windows远程Ubnuntu进行ssh、VNC和打开…

Nature -- 空间表观组学与转录组学联合分析,揭示基因表达的精准调控

为充分理解组织中单细胞的基因表达调控&#xff0c;需要在单细胞水平以空间分辨率的方式集成不同分子信息的不同层面&#xff0c;包括表观基因组和转录组数据。虽然单细胞多组学方法可以捕捉来自不同分子层的信息&#xff0c;但是空间组学方法到目前为止主要局限于一层分子。张…

MATLAB的无人机遥感数据预处理与农林植被性状估算实践

在新一轮互联网信息技术大发展的现今&#xff0c;无人机、大数据、人工智能、物联网等新兴技术在各行各业都处于大爆发的前夜。为了将人工智能方法引入农业生产领域。首先在种植、养护等生产作业环节&#xff0c;逐步摆脱人力依赖&#xff1b;在施肥灌溉环节构建智慧节能系统&a…

ASP.NET core WebApi Cors跨域解决

前言 我用了最新版的Asp.net webapi &#xff0c;在csdn上面搜跨域如何解决的时候&#xff0c;发现csdn上面对于.NET技术讨论不是很多。没办法&#xff0c;只能面向官方文档和GitHub编程了。 项目类型确认 NuGet包引入 前面两个已经放弃维护了&#xff0c;我们就不用了。用最…

使用Actor-Critic的DDPG强化学习算法控制双关节机械臂

在本文中&#xff0c;我们将介绍在 Reacher 环境中训练智能代理控制双关节机械臂&#xff0c;这是一种使用 Unity ML-Agents 工具包开发的基于 Unity 的模拟程序。 我们的目标是高精度的到达目标位置&#xff0c;所以这里我们可以使用专为连续状态和动作空间设计的最先进的Deep…

【uni-app】errMsg : navigateTo:fail can not navigateTo a tabbar page报错解决方案

文章目录 前言一、报错二、解决方案更改api 总结 前言 大家好&#xff0c;今天在进行uni-app项目开发时&#xff0c;在进行页面跳转的时候报了一个错误&#xff0c;一开始觉得只是个小报错就没有仔细看这个报错&#xff0c;直接就到页面检查看是不是跳转没写好&#xff0c;但是…

Spring IOC:详解【依赖注入数值问题 依赖注入方式】

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 Maven版本&#xff1a;apache-maven-3.6.3 Mybatis版本&#xff1a;3.5.6 spring版本&#xff1a;5.3.1 文章目录 Spring系列专栏文章目录一、Spring依赖注入数值问题1.1 字面量数值问…

计算机网络 | 广播与组播

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

Jetpack之livedata原理分析

1.LiveData是什么&#xff1f; 只有在生命周期处于started和resumed时。livedata才会更新观察者 2.Livedata的各种使用方式 1.更新数据 class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceSta…

Python数据分析实战【十四】:python的三种排序方法:sort、sorted、sort_values案例学习【文末源码地址】

文章目录 一、List.sort()排序案例一&#xff1a;按照列表中的元素进行排序案例二&#xff1a;按照销售额数据进行排列 二、sorted()排序案例一&#xff1a;sorted()对列表进行排序案例二&#xff1a;sorted()对字典进行排序案例三&#xff1a;sorted()对列表中的字典元素排序 …

【AI大模型】国产AI技术再创新高,讯飞星火认知大模型中文能力已经超越ChatGPT?

文章目录 前言SparkDesk讯飞星火认知大模型简介语言理解知识问答逻辑推理数学题解答代码理解与编写亲自体验写在最后 前言 5月6日&#xff0c;讯飞星火认知大模型成果发布会在安徽合肥举行。科大讯飞董事长刘庆峰、研究院院长刘聪发布讯飞星火认知大模型&#xff0c;现场实测大…

(一)ArcGIS空间数据的转换与处理——投影变换

ArcGIS空间数据的转换与处理——投影变换 原始数据往往由于在数据结构、数据组织、数据表达等方面与用户需求不一致而要进行转换与处理。本节主要介绍 ArGIS 中数据的投影变换内容。 目录 ArcGIS空间数据的转换与处理——投影变换 1.概述2.定义投影3.投影变换3.1栅格数据的投…

Python数据分析实战【十四】:Python的三种排序方法:sort()、sorted()和sort_values()【文末源码地址】

文章目录 一、List.sort()排序案例一&#xff1a;按照列表中的元素进行排序案例二&#xff1a;按照销售额数据进行排列 二、sorted()排序案例一&#xff1a;sorted()对列表进行排序案例二&#xff1a;sorted()对字典进行排序案例三&#xff1a;sorted()对列表中的字典元素排序 …