Kubernets-腾讯云TKE

文章目录

目的篇

现有体系分析
  • 成本伴随着服务规模的扩大会越来越高
  • 服务器规模伴随着服务规模的扩大会越来越庞大
  • 虚拟机性能利用率不高
  • 无法自动扩容,自动调度,自动重启
期望Docker+Kubernetes的效果
  • 快速部署应用,快速扩展应用
  • 无缝对接新的应用功能节省资源,优化硬件资源的使用
  • 交付、部署:虚拟机可以通过镜像实现环境交付的一致性
  • 可扩展: 模块化,插件化,可挂载,可组合
  • 自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展

传统虚拟化与Docker对比

在这里插入图片描述在这里插入图片描述

虚拟机概述

虚拟机在本质上就是在模拟一台真实的计算机设备,同时遵循同样的程序执行方式。虚拟机能够利用“虚拟机管理程序”运行在物理设备之上。反过来,虚拟机管理程序则可运行在主机设备或者“裸机”之上。
传统的虚拟机需要模拟整台机器包括硬件,每台虚拟机都需要有自己的操作系统,虚拟机一旦被开启,预分配给他的资源将全部被占用。,每一个虚拟机包括应用,必要的二进制和库,以及一个完整的用户操作系统。

Docker虚拟化的架构

其中Docker Engine可以简单看成对Linux的NameSpace、Cgroup、镜像管理文件系统操作的封装。Docker并没有和虚拟机一样利用一个完全独立的Guest OS实现环境隔离,它利用的是目前linux内核本身支持的容器方式实现资源和环境隔离。简单的说,Docker是利用namespace实现系统环境的隔离;利用Cgroup实现资源限制;利用镜像实现根目录环境的隔离。

docker化优点
  • Docker启动快速属于秒级别。虚拟机通常需要几分钟去启动。

  • Docker在操作系统级别进行虚拟化,Docker容器和内核交互,几乎没有性能损耗,性能优于通过Hypervisor层与内核层的虚拟化。

  • Docker更轻量,Docker的架构可以共用一个内核与共享应用程序库,所占内存极小。同样的硬件环境,Docker运行的镜像数远多于虚拟机数量。对系统的利用率非常高。与虚拟机相比,Docker隔离性更弱,Docker属于进程之间的隔离,虚拟机可实现系统级别隔离。

  • 安全性:Docker的安全性也更弱。Docker的租户root和宿主机root等同,一旦容器内的用户从普通用户权限提升为root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。虚拟机租户root权限和宿主机的root虚拟机权限是分离的,并且虚拟机利用如Intel的VT-d和VT-x的ring-1硬件隔离技术,这种隔离技术可以防止虚拟机突破和彼此交互,而容器至今还没有任何形式的硬件隔离,这使得容器容易受到攻击。

  • 可管理性:Docker的集中化管理工具还不算成熟。各种虚拟化技术都有成熟的管理工具,例如VMware vCenter提供完备的虚拟机管理能力。

  • 高可用和可恢复性:Docker对业务的高可用支持是通过快速重新部署实现的。虚拟化具备负载均衡、高可用、容错、迁移和数据保护等经过生产实践检验的成熟保障机制,VMware可承诺虚拟机99.999%高可用,保证业务连续性。

  • 快速创建、删除:虚拟化创建是分钟级别的,Docker容器创建是秒级别的,Docker的快速迭代性,决定了无论是开发、测试、部署都可以节约大量时间。

  • 交付、部署:虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化;Docker在Dockerfile中记录了容器构建过程,可在集群中实现快速分发和快速部署。

K8S 优点

  • 快速部署应用,快速扩展应用
  • 无缝对接新的应用功能节省资源,优化硬件资源的使用
  • 可移植: 支持公有云,私有云,混合云,多重云(multi-cloud)
  • 可扩展: 模块化,插件化,可挂载,可组合
  • 自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展

概念篇

Dcoker相关

Dcoker是什么

Docker是一个集开发、打包、运行应用于一体的开放式平台。Docker可以用来快速交付应用。使用Docker,你可以将应用程序从你的基础设施中分离出来,并将基础设施当做一个管理平台。Docker可以加快打包时间,加快测试,加快发布,缩短开发及运行代码之间的周期。Docker通过结合内核容器化特点和工作流,并使之工具化来实现这一切,帮助管理和发布你的应用。

Docker 镜像

Docker镜像是一个只读的模板。包含了容器运行时所需要的文件系统和一些参数。镜像是无状态的,也不会改变。镜像是用来创建容器的。你可以使用docker pull命令获取一个别人已创建好的镜像,或者使用dockerbuild来构建一个自己的镜像。

Docker 容器

Docker容器就像是一个文件夹,容器中包含了应用运行所需的一切。每个容器都是一个隔离的和安全的应用平台。容器是镜像的一个实例,它是有状态的,而且随时会改变,容器一般是短暂的。

Docker Daemon

Docker Daemon直接将执行命令发送至Docker Client——例如构建、运行以及分发等等。Docker Daemon运行在主机设备之上,但作为用户,我们永远不会直接与该Daemon进行通信。Docker Client也可以运行在主机设备上,但并非必需。它亦能够运行在另一台设备上,并与运行在目标主机上的Docker Daemon进行远程通信。

Docker Client

Docker Client是我们作为最终用户的通信对象。我们可以将其视为Docker的UI。我们进行的一切操作都将直接接入Docker Client,再由其将指令传递至Docker Daemon。

Docker API

用于同Docker Daemon远程交互。

Docker 应用场景
  • web应用的自动化打包和发布;
  • 自动化测试和持续集成、发布;
  • 在服务型环境中部署和调整数据库或其他的后台应用;
  • 从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境。

Kubernetes相关

K8S是什么

Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。
Kubernetes是Google 2014年创建管理的,是Google 10多年大规模容器管理技术Borg的开源版本

TKE是什么

腾讯云容器服务(Tencent Kubernetes Engine,TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务。腾讯云容器服务完全兼容原生 kubernetes API ,扩展了腾讯云的 CBS、CLB 等 kubernetes 插件,为容器化的应用提供高效部署、资源调度、服务发现和动态伸缩等一系列完整功能,解决用户开发、测试及运维过程的环境一致性问题,提高了大规模容器集群管理的便捷性,帮助用户降低成本,提高效率。容器服务提供免费使用,涉及的其他云产品另外单独计费。

K8S架构图及应用集群节点说明

在这里插入图片描述

Pod

pod运行在Node上,包含一组容器和卷。同一个Pod里的容器共享同一个网络命名空间,可以使用localhost互相通信。Pod是短暂的,不是持续性实体。你可能会有这些问题:

  • 如果Pod是短暂的,那么我怎么才能持久化容器数据使其能够跨重启而存在呢? 是的,Kubernetes支持卷的概念,因此可以使用持久化的卷类型。
  • 是否手动创建Pod,如果想要创建同一个容器的多份拷贝,需要一个个分别创建出来么?可以手动创建单个Pod,但是也可以使用Replication Controller使用Pod模板创建出多份拷贝
  • 如果Pod是短暂的,那么重启时IP地址可能会改变,那么怎么才能从前端容器正确可靠地指向后台容器呢?这时可以使用Service

Pod的生命周期:

  • Pending Pod:Pod已经被创建,但是一个或多个容器还未创建,包括Pod调度阶段,以及容器镜像的下载过程
  • Running: Pod已经被调度到Node,所有容器已经创建,并且至少一个容器在运行或者正在重启。
  • Successded: Pod中所有容器正常退出
  • Failed: Pod中所有容器推出,至少有一个容器时一次退出的
Lable

一些Pod有Label([外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BaN3FLeV-1589009640677)(en-resource://database/730:1)])。一个Label是attach到Pod的一对键/值对,用来传递用户定义的属性。比如,你可能创建了一个"tier"和“app”标签,通过Label(tier=frontend, app=myapp)来标记前端Pod容器,使用Label(tier=backend, app=myapp)标记后台Pod。然后可以使用Selectors选择带有特定Label的Pod,并且将Service或者Replication Controller应用到上面。

Replication Controller

是否手动创建Pod,如果想要创建同一个容器的多份拷贝,需要一个个分别创建出来么,能否将Pods划到逻辑组里?
Replication Controller确保任意时间都有指定数量的Pod“副本”在运行。如果为某个Pod创建了Replication Controller并且指定3个副本,它会创建3个Pod,并且持续监控它们。如果某个Pod不响应,那么Replication Controller会替换它,保持总数为3.如下面的动画所示:
在这里插入图片描述

如果之前不响应的Pod恢复了,现在就有4个Pod了,那么Replication Controller会将其中一个终止保持总数为3。如果在运行中将副本总数改为5,Replication Controller会立刻启动2个新Pod,保证总数为5。还可以按照这样的方式缩小Pod,这个特性在执行滚动升级时很有用。
当创建Replication Controller时,需要指定两个东西:

  • Pod模板:用来创建Pod副本的模板

  • Label:Replication Controller需要监控的Pod的标签。
    现在已经创建了Pod的一些副本,那么在这些副本上如何均衡负载呢?我们需要的是Service

    Service

如果Pods是短暂的,那么重启时IP地址可能会改变,怎么才能从前端容器正确可靠地指向后台容器呢?
Service是定义一系列Pod以及访问这些Pod的策略的一层抽象。Service通过Label找到Pod组。因为Service是抽象的,所以在图表里通常看不到它们的存在,这也就让这一概念更难以理解。
现在,假定有2个后台Pod,并且定义后台Service的名称为‘backend-service’,lable选择器为(tier=backend, app=myapp)。backend-service 的Service会完成如下两件重要的事情:

  • 会为Service创建一个本地集群的DNS入口,因此前端Pod只需要DNS查找主机名为 ‘backend-service’,就能够解析出前端应用程序可用的IP地址。

  • 现在前端已经得到了后台服务的IP地址,但是它应该访问2个后台Pod的哪一个呢?Service在这2个后台Pod之间提供透明的负载均衡,会将请求分发给其中的任意一个(如下面的动画所示)。通过每个Node上运行的代理(kube-proxy)完成。这里有更多技术细节。

下述动画展示了Service的功能。注意该图作了很多简化。如果不进入网络配置,那么达到透明的负载均衡目标所涉及的底层网络和路由相对先进。如果有兴趣,这里有更深入的介绍。
在这里插入图片描述
有一个特别类型的Kubernetes Service,称为'LoadBalancer',作为外部负载均衡器使用,在一定数量的Pod之间均衡流量。比如,对于负载均衡Web流量很有用。

service的类型
  • ClusterIP 默认模式,只能在集群内部访问
  • NodePort 在每个节点上都监听一个同样的端口号(30000-32767),ClusterIP和路由规则会自动创建。集群外部可以访问:联系到集群内部服务,可以配合外部负载均衡使用
  • LoadBalancer 要配合支持公有云负载均衡使用比如GCE、AWS。其实也是NodePort,只不过会把:自动添加到公有云的负载均衡当中
  • ExternalName 创建一个dns别名指到service name上,主要是防止service name发生变化,要配合dns插件使用
Node

节点(上图橘色方框)是物理或者虚拟机器,作为Kubernetes worker,通常称为Minion。每个节点都运行如下Kubernetes关键组件:

  • Kubelet:是主节点代理。
  • Kube-proxy:Service使用其将链接路由到Pod,如上文所述。
  • Docker或Rocket:Kubernetes使用的容器技术来创建容器。
Kubernetes Master

集群拥有一个Kubernetes Master(紫色方框)。Kubernetes Master提供集群的独特视角,并且拥有一系列组件,比如Kubernetes API Server。API Server提供可以用来和集群交互的REST端点。master节点包括用来创建和复制Pod的Replication Controller。

Deployment
  • Deployment:负责控制Pod的生命周期、保证服务有一定数量的Pod在运行。Deployment定义了Pod内容,包括Pod数量、更新方式、使用的镜像,资源限制等等。
  • StatefulSet:管理应用程序的工作负载 API 对象,且该应用程序为有状态的应用程序。
  • DaemonSet:确保所有或部分节点上运行 Pod,例如日志采集。
  • Job:一个 Job 创建一个或多个 Pod,直至运行结束。
  • CronJob:定时运行的 Job 任务。
Ingress

通常情况下,service和pod仅可在集群内部网络中通过IP地址访问。所有到达边界路由器的流量或被丢弃或被转发到其他地方。从概念上讲,可能像下面这样:

internet --> service

Ingress是授权入站连接到达集群服务的规则集合。

internet -->ingress --> service

你可以给Ingress配置提供外部可访问的URL、负载均衡、SSL、基于名称的虚拟主机等。用户通过POST Ingress资源到API server的方式来请求ingress。 Ingress controller负责实现Ingress,通常使用负载平衡器,它还可以配置边界路由和其他前端,这有助于以HA方式处理流量。
Ingress与腾讯云的CLB类似,可以提供根据url进行转发的功能,与Service最根本的区别就是Service不能根据url进行转发只能定义端口转发与负载方式如公网访问,集群内访问等。两者互补。
(K8S是使用IP tables的nat表进行转发,腾讯针对IP tables在大并发情况下的性能差二次开发了IPVS)

NameSpace

对资源进行隔离,不同NameSpace空间的资源无法互相访问,可不同业务分配不同的命名空间。
当团队或项目中具有许多用户时,可以考虑使用Namespace来区分,a如果是少量用户集群,可以不需要考虑使用Namespace,如果需要它们提供特殊性质时,可以开始使用Namespace。Namespace为名称提供了一个范围。资源的Names在Namespace中具有唯一性。
Namespace是一种将集群资源划分为多个用途(通过 resource quota)的方法。
在未来的Kubernetes版本中,默认情况下,相同Namespace中的对象将具有相同的访问控制策略。对于稍微不同的资源没必要使用多个Namespace来划分,例如同意软件的不同版本,可以使用labels(标签)来区分同一Namespace中的资源。

Persistent Volumes(PV)

集群内的存储资源,例如节点是集群的资源。PV 独立于 Pod 的生命周期,根据不同的 StorageClass 类型创建不同类型的 PV。

Persistent Volume 简称PV是一个K8S资源对象,我们可以单独创建一个PV。它不和Pod直接发生关系,而是通过Persistent Volume Claim,简称PVC来实现动态绑定。Pod定义里指定的是PVC,然后PVC会根据Pod的要求去自动绑定合适的PV给Pod使用。

PersistentVolumeClaim(PVC)

PersistentVolumeClaim(PVC):集群内的存储请求。例如,PV 是 Pod 使用节点资源,PVC 则声明使用 PV 资源。当 PV 资源不足时,PVC 也可以动态创建 PV。

服务的自动扩容算法

服务自动扩缩容后台组件会定期(30s)向腾讯云云监控拉取容器和 POD 的监控指标,然后根据该指标当前值,当前副本数和该指标目标值计算出目标副本数,然后以该目标副本数作为服务的期望副本数,达到自动伸缩的目的。 比如当前有 2 个实例, 平均 CPU 利用率为 90%,服务自动伸缩设置目标 CPU 为 60%, 则自动调整实例数量为:90% * 2 / 60% = 3 个。如果用户设置了多个弹性伸缩指标,HPA 会依据各个指标,分别计算出目标副本数,然后取最大的一个作为最终目标副本数。—TKE文档中心

Node的自动扩容

K8S核心组件

Kubernetes遵循master-slave architecture。Kubernetes的组件可以分为管理单个的 node 组件和控制平面的一部分的组件。
Kubernetes Master是集群的主要控制单元,用于管理其工作负载并指导整个系统的通信。Kubernetes控制平面由各自的进程组成,每个组件都可以在单个主节点上运行,也可以在支持high-availability clusters的多个主节点上运行。
Kubernetes主要由以下几个核心组件组成:
在这里插入图片描述

核心组件结构图
在这里插入图片描述
 除了核心组件,还有一些推荐的Add-ons:
在这里插入图片描述

实操篇

服务的自动扩容

自动扩容其实是K8S判断POD的一些硬件指标(CPU使用率,带宽等)是否达到了预警值,如果达到了,就行扩容,没有到不变

命令行方式实现

kubectl autoscale deployment php-apache --min=1 --max=10 --cpu-percent=50

最小Pod数量为1,最大为10,当CPU使用率超过50%时触发

yaml文件中指定
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1beta1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50
TKE 控制台创建Deployment时指定

在这里插入图片描述

有状态的服务如何通过deployment创建

镜像的对接

1.先从docker hub上找到nginx 或tomcat指定版本的官方Dokcer file构建生成基础镜像,并推到私有仓库中
基础openresty镜像例子:

# Dockerfile - alpine
# https://github.com/openresty/docker-openresty

ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.9"

FROM ${RESTY_IMAGE_BASE}:${RESTY_IMAGE_TAG}

LABEL maintainer="Evan Wies <[email protected]>"

# Docker Build Arguments
ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.9"
ARG RESTY_VERSION="1.15.8.1"
ARG RESTY_OPENSSL_VERSION="1.1.1c"
ARG RESTY_PCRE_VERSION="8.42"
ARG RESTY_J="1"
ARG RESTY_CONFIG_OPTIONS="\
    --with-compat \
    --with-file-aio \
    --with-http_addition_module \
    --with-http_auth_request_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_geoip_module=dynamic \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_image_filter_module=dynamic \
    --with-http_mp4_module \
    --with-http_random_index_module \
    --with-http_realip_module \
    --with-http_secure_link_module \
    --with-http_slice_module \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_sub_module \
    --with-http_v2_module \
    --with-http_xslt_module=dynamic \
    --with-ipv6 \
    --with-mail \
    --with-mail_ssl_module \
    --with-md5-asm \
    --with-pcre-jit \
    --with-sha1-asm \
    --with-stream \
    --with-stream_ssl_module \
    --with-threads \
    "
ARG RESTY_CONFIG_OPTIONS_MORE=""
ARG RESTY_LUAJIT_OPTIONS="--with-luajit-xcflags='-DLUAJIT_NUMMODE=2 -DLUAJIT_ENABLE_LUA52COMPAT'"

ARG RESTY_ADD_PACKAGE_BUILDDEPS=""
ARG RESTY_ADD_PACKAGE_RUNDEPS=""
ARG RESTY_EVAL_PRE_CONFIGURE=""
ARG RESTY_EVAL_POST_MAKE=""

# These are not intended to be user-specified
ARG _RESTY_CONFIG_DEPS="--with-openssl=/tmp/openssl-${RESTY_OPENSSL_VERSION} --with-pcre \
    --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include' \
    --with-ld-opt='-L/usr/local/openresty/pcre/lib -Wl,-rpath,/usr/local/openresty/pcre/lib' \
    "

LABEL resty_image_base="${RESTY_IMAGE_BASE}"
LABEL resty_image_tag="${RESTY_IMAGE_TAG}"
LABEL resty_version="${RESTY_VERSION}"
LABEL resty_openssl_version="${RESTY_OPENSSL_VERSION}"
LABEL resty_pcre_version="${RESTY_PCRE_VERSION}"
LABEL resty_config_options="${RESTY_CONFIG_OPTIONS}"
LABEL resty_config_options_more="${RESTY_CONFIG_OPTIONS_MORE}"
LABEL resty_config_deps="${_RESTY_CONFIG_DEPS}"
LABEL resty_add_package_builddeps="${RESTY_ADD_PACKAGE_BUILDDEPS}"
LABEL resty_add_package_rundeps="${RESTY_ADD_PACKAGE_RUNDEPS}"
LABEL resty_eval_pre_configure="${RESTY_EVAL_PRE_CONFIGURE}"
LABEL resty_eval_post_make="${RESTY_EVAL_POST_MAKE}"

# 1) Install apk dependencies
# 2) Download and untar OpenSSL, PCRE, and OpenResty
# 3) Build OpenResty
# 4) Cleanup

RUN apk add --no-cache --virtual .build-deps \
        build-base \
        coreutils \
        curl \
        gd-dev \
        geoip-dev \
        libxslt-dev \
        linux-headers \
        make \
        perl-dev \
        readline-dev \
        zlib-dev \
        ${RESTY_ADD_PACKAGE_BUILDDEPS} \
    && apk add --no-cache \
        bash \
        bash-doc \
        bash-completion \
        gd \
        geoip \
        libgcc \
        libxslt \
        zlib \
        ${RESTY_ADD_PACKAGE_RUNDEPS} \
    && cd /tmp \
    && if [ -n "${RESTY_EVAL_PRE_CONFIGURE}" ]; then eval $(echo ${RESTY_EVAL_PRE_CONFIGURE}); fi \
    && curl -fSL https://www.openssl.org/source/openssl-${RESTY_OPENSSL_VERSION}.tar.gz -o openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
    && tar xzf openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
    && curl -fSL https://ftp.pcre.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz \
    && tar xzf pcre-${RESTY_PCRE_VERSION}.tar.gz \
    && cd /tmp/pcre-${RESTY_PCRE_VERSION} \
    && ./configure \
        --prefix=/usr/local/openresty/pcre \
        --disable-cpp \
        --enable-jit \
        --enable-utf \
        --enable-unicode-properties \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install \
    && cd /tmp \
    && curl -fSL https://openresty.org/download/openresty-${RESTY_VERSION}.tar.gz -o openresty-${RESTY_VERSION}.tar.gz \
    && tar xzf openresty-${RESTY_VERSION}.tar.gz \
    && cd /tmp/openresty-${RESTY_VERSION} \
    && if [[ "1.1.1" == $(echo -e "${RESTY_OPENSSL_VERSION}\n1.1.1" | sort -V | head -n1) ]] ; then \
        echo 'patching Nginx for OpenSSL 1.1.1' \
        && cd bundle/nginx-1.15.8 \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.15.8-ssl_cert_cb_yield.patch | patch -p1 \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.15.8-ssl_sess_cb_yield.patch | patch -p1 \
        && cd ../.. ; \
    fi \
    && eval ./configure -j${RESTY_J} ${_RESTY_CONFIG_DEPS} ${RESTY_CONFIG_OPTIONS} ${RESTY_CONFIG_OPTIONS_MORE} ${RESTY_LUAJIT_OPTIONS} \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install \
    && cd /tmp \
    && if [ -n "${RESTY_EVAL_POST_MAKE}" ]; then eval $(echo ${RESTY_EVAL_POST_MAKE}); fi \
    && rm -rf \
        openssl-${RESTY_OPENSSL_VERSION} \
        openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
        openresty-${RESTY_VERSION}.tar.gz openresty-${RESTY_VERSION} \
        pcre-${RESTY_PCRE_VERSION}.tar.gz pcre-${RESTY_PCRE_VERSION} \
    && apk del .build-deps \
    && ln -sf /dev/stdout /usr/local/openresty/nginx/logs/access.log \
    && ln -sf /dev/stderr /usr/local/openresty/nginx/logs/error.log

# Add additional binaries into PATH for convenience
ENV PATH=$PATH:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin:/bin/bash

# Copy nginx configuration files
COPY conf/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY conf/nginx.conf /etc/nginx/conf.d/default.conf

#CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]
CMD ["bash"]
# Use SIGQUIT instead of default SIGTERM to cleanly drain requests
# See https://github.com/openresty/docker-openresty/blob/master/README.md#tips--pitfalls
STOPSIGNAL SIGQUIT

在这里插入图片描述
构建时使用docker build --tag 或构建完成后使用docker --tag imageid imagename:version

docker login url #登陆私有仓库
docker tag 5787d71f774c shjrccr.ccs.tencentyun.com/yw/openresty:1.15.8.1-alpine-fat-apph5 #更改镜像名称
docker push shjrccr.ccs.tencentyun.com/yw /openresty:1.15.8.1-alpine-fat-apph5 #推送镜像到私有仓库

基于刚才构建的openresty基础镜像,进行二次构建
业务nginx镜像:

FROM  shjrccr.ccs.tencentyun.com/yw/openresty:1.15.8.1-alpine-fat

MAINTAINER WQ

ADD conf/nginx.conf /usr/local/openresty/nginx/conf/
RUN mkdir -pv  /app/public/view/ /app/logs
ADD pro/appH5 /app/public/view/

#CMD ["bash"]
CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]

将此业务镜像推到私有仓库即可
在这里插入图片描述

日志的输出与NFS类型的PV PVC

新建NFS服务器

安装软件包,启动服务并添加至开机自启

yum install -y rpcbind nfs-utils
systemctl start rpcbind
systemctl enable rpcbind
systemctl start nfs-server
systemctl enable nfs-server

修改配置文件,并重读配置文件

[root@VM_1_11_centos ~]# cat /etc/exports
/opt/logs *(rw,sync,no_root_squash)
exportfs -r

命令行方式创建pv,pvc

TKE 控制台无法直接创建nfs pv和nfs pvc可在创建deployment时选择已有nfs

登陆任意Node节点,创建PV

[root@VM_1_14_centos k8s_test]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvnfs 50Gi RWO Retain Bound default/nfsclaim pvnfs 2d23h
[root@VM_1_14_centos k8s_test]# kubectl create -f pv_nfs.yaml

pv_nfs.yaml实例

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvnfs
  namespace: default
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /opt/logs
    server: 10.2.1.11
  storageClassName: pvnfs
创建pvc

[root@VM_1_14_centos k8s_test]# kubectl create -f pvc_nfs.yaml
[root@VM_1_14_centos k8s_test]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfsclaim Bound pvnfs 50Gi RWO pvnfs 2d23h

pvc_nfs.yaml实例:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nfsclaim
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: pvnfs
创建deployment

[root@VM_1_14_centos k8s_test]# kubectl create -f nginx_deployment.yaml
[root@VM_1_14_centos k8s_test]# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
lbapph5 3 3 3 3 2d22h

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-apph5
  labels:
    app: nginx-deployment-apph5
    vers: v02
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-deployment-apph5
      vers: v02
  template:
    metadata:
      labels:
        app: nginx-deployment-apph5
        vers: v02
    spec:
      containers:
      - image: shjrccr.ccs.tencentyun.com/yw/openresty:v1apph5v0.2
        imagePullPolicy: IfNotPresent
        name: apph5v02
        volumeMounts:
        - mountPath: "/app/logs/"
          name: nginx-nfs-pvc
      imagePullSecrets:
      - name: w-dr

      volumes:
      - name: nginx-nfs-pvc
        persistentVolumeClaim:
          claimName: nfsclaim

service的创建

[root@VM_1_14_centos k8s_test]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.16.255.1 443/TCP 6d23h
lbapph5 LoadBalancer 172.16.255.45 211.159.251.238 8000:30709/TCP 2d22h
[root@VM_1_14_centos k8s_test]# kubectl create -f service.yaml

实例:

apiVersion: v1
kind: Service
metadata:
  name: apph5-service
  labels:
    name: apph5-service
spec:
  type: NodePort      #这里代表是NodePort类型的
  ports:
  - port: 80          #这里的端口和clusterIP(10.97.114.36)对应,即10.97.114.36:80,供内部访问。
    targetPort: 8000  #端口一定要和container暴露出来的端口对应,nodejs暴露出来的端口是8081,所以这里也应是8081
    protocol: TCP
    nodePort: 32143   # 所有的节点都会开放此端口,此端口供外部调用。
  selector:
    app: nginx-deployment-apph5
    vers: v02

创建方式:

  • 可直接通过kuberctl create/apply -f servicename.yaml
  • 也可通过TKE控制面板创建
    在这里插入图片描述
service 与CLB绑定

service类型选择NodePort,CLB绑定Node节点

在这里插入图片描述

登陆nfs服务器查看日志

多个容器日志会吐到同一文件
在这里插入图片描述

K8S相关角色配置文件示例

Node

有两种创建方式:

  • 新增节点
  • 添加已有节点

在这里插入图片描述

Pod

实例:

apiVersion: v1
kind: Pod
metadata:
  name: apph5pod
spec:
  containers:
    - name: apph5pod
      image: shjrccr.ccs.tencentyun.com/yw/openresty:v1apph5v0.1
      imagePullPolicy: Always
  imagePullSecrets:
    - name: w-dr

在任意一台Node上面通过命令kubectl 创建

kubectl [option] name
kubectl get podname -o wide/json/…

创建Pod以及查看:

[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
apph5pod 1/1 Running 0 15m
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m
[root@VM_1_14_centos k8s_test]# kubectl delete pod apph5pod
pod “apph5pod” deleted
[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m
[root@VM_1_14_centos k8s_test]# kubectl create -f pod.yaml
pod/apph5pod created
[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
apph5pod 1/1 Running 0 4s
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m

PV

硬盘类型PV实例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nginx-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  qcloudCbs:
      cbsDiskId: disk-qlaxhjzq ## 指定已有的CBS id
      fsType: ext4
  storageClassName: cbs

NFS类型实例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvnfs
  namespace: default
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /opt/logs
    server: 10.2.1.11
  storageClassName: pvnfs

accessModes:

  • ReadWriteOnce:数据卷能够在一个节点上挂载为读写目录
  • ReadWriteMany:数据卷能够在多个节点上挂载为读写目录
  • ReadOnlyMany: 数据卷能够在多个节点上挂载为读写目录

PV回收策略:

  • Retain:PV释放后,需要人工进行回收操作
    
  • Recycle:PV释放后,K8S自动进行清理,清理成功后PV则可以在此绑定使用,目前只有NFS和HostPath类型的PV支持回收策略。当执行回收策略时,会创建一个PV Recycler Pod,这个Pod执行清理操作,即删除PV目录下的所有文件 含隐藏文件。

创建方式:

  • 可直接通过kuberctl create/apply -f pv.yaml
  • 也可以通过TKE控制台创建,控制台只能创建硬盘类型的PV
    在这里插入图片描述
POD

apiVersion: v1            //版本
kind: pod                 //类型,pod
metadata:                 //元数据
  name: String            //元数据,pod的名字
  namespace: String       //元数据,pod的命名空间
  labels:                 //元数据,标签列表
    - name: String        //元数据,标签的名字
  annotations:            //元数据,自定义注解列表
    - name: String        //元数据,自定义注解名字
spec:                     //pod中容器的详细定义
  containers:             //pod中的容器列表,可以有多个容器
  - name: String
    image: String         //容器中的镜像
    imagesPullPolicy: [Always|Never|IfNotPresent]//获取镜像的策略
    command: [String]     //容器的启动命令列表(不配置的话使用镜像内部的命令)
    args: [String]        //启动参数列表
    workingDir: String    //容器的工作目录
    volumeMounts:         //挂载到到容器内部的存储卷设置
    - name: String
      mountPath: String
      readOnly: boolean
    ports:                //容器需要暴露的端口号列表
    - name: String
      containerPort: int  //容器要暴露的端口
      hostPort: int       //容器所在主机监听的端口(容器暴露端口映射到宿主机的端口)
      protocol: String
    env:                  //容器运行前要设置的环境列表
    - name: String
      value: String
    resources:            //资源限制
      limits:
        cpu: Srting
        memory: String
      requeste:
        cpu: String
        memory: String
    livenessProbe:         //pod内容器健康检查的设置
      exec:
        command: [String]
      httpGet:             //通过httpget检查健康
        path: String
        port: number
        host: String
        scheme: Srtring
        httpHeaders:
        - name: Stirng
          value: String 
      tcpSocket:           //通过tcpSocket检查健康
        port: number
      initialDelaySeconds: 0//首次检查时间
      timeoutSeconds: 0     //检查超时时间
      periodSeconds: 0      //检查间隔时间
      successThreshold: 0
      failureThreshold: 0
      securityContext:      //安全配置
        privileged: falae
    restartPolicy: [Always|Never|OnFailure]//重启策略
    nodeSelector: object    //节点选择
    imagePullSecrets:
    - name: String
    hostNetwork: false      //是否使用主机网络模式,默认否
  volumes:                  //在该pod上定义共享存储卷
  - name: String
    meptyDir: {}
    hostPath:
      path: string
    secret:                 //类型为secret的存储卷
      secretName: String
      item:
      - key: String
        path: String
    configMap:             //类型为configMap的存储卷
      name: String
      items:
      - key: String
        path: String
健康检测
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /demo/sql
            port: 9000
            scheme: HTTP
          initialDelaySeconds: 30
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 30
        name: sim-credit-auto
        readinessProbe:
          failureThreshold: 5
          httpGet:
            path: /demo/sql
            port: 9000
            scheme: HTTP
          initialDelaySeconds: 30
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 30
PVC

NFS-PV实例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-ali
  namespace: sim-bis
  labels:
    pv: pv-nfs-ali
spec:
  capacity:
    storage: 500Mi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /sim/bis/tomcat/ali
    server: 10.2.1.6
  storageClassName: sim-b-tomcat

指定pv的PVC实例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-ali
  namespace: sim-b
  labels:
    pv: pv-nfs-ali
spec:
  capacity:
    storage: 500Mi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /sim/bis/tomcat/ali
    server: 10.2.1.6
  storageClassName: sim-b-tomcat

创建方式:

  • 可直接通过kuberctl create/apply -f pvc.yaml
  • 也可通过TKE控制面板创建

在这里插入图片描述

Deployment

实例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dm-tomcat-auto
  labels:
    app: dm-tomcat-auto
    vers: v01
  namespace: sim-credit
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dm-tomcat-auto
      vers: v01
  template:
    metadata:
      labels:
        app: dm-tomcat-auto
        vers: v01
    spec:
      containers:
      - image: shjrccr.ccs.tencentyun.com/sim_credit/tomcat_base:v01
        imagePullPolicy: Always
        name: dm-tomcat-auto
        livenessProbe:
          httpGet:
            path: /demo/sql
            port: 9000
          #  host: localhost
            scheme: HTTP
          initialDelaySeconds: 90
          timeoutSeconds: 10
        volumeMounts:
        - mountPath: "/opt/apache-tomcat-8.5.14/webapps/"
          name: pvc-nfs-auto-war
        - mountPath: "/opt/apache-tomcat-8.5.14/logs/"
          name: pvc-nfs-auto-log
      imagePullSecrets:
      - name: qcloudregistrykey

      volumes:
      - name: pvc-nfs-auto-war
        persistentVolumeClaim:
          claimName: pvc-nfs-auto-war
      - name: pvc-nfs-auto-log
        persistentVolumeClaim:
          claimName: pvc-nfs-auto-log

创建方式:

  • 可直接通过kuberctl create/apply -f deploymentname.yaml
  • 也可通过TKE控制面板创建,控制面板创建会一起创建Service
    在这里插入图片描述
service
apiVersion: v1
kind: Service
metadata:
  name: apph5-service
  labels:
    name: apph5-service
spec:
  type: NodePort      #这里代表是NodePort类型的
  ports:
  - port: 80          #这里的端口和clusterIP(10.97.114.36)对应,即10.97.114.36:80,供内部访问。
    targetPort: 8000  #端口一定要和container暴露出来的端口对应,nodejs暴露出来的端口是8081,所以这里也应是8081
    protocol: TCP
    nodePort: 32143   # 所有的节点都会开放此端口,此端口供外部调用。
  selector:
    app: nginx-deployment-apph5
    vers: v02

Docker镜像相关

镜像对比
  • alpine 小巧,只有5M,依赖包较少
  • centos 200M左右,各种依赖包,字体等全
基础镜像

思路:通过dockerhub中官方提供的DockerFile构建成基础镜像–基于此基础镜像,此基础镜像放到私有仓库中(涉及私有仓库命名)-- 再构建时将项代码放进入

K8S命令

1、kubectl create -f nginx-deployment.yaml
2、查看deployment
kubectl get deployment
3、查看pod
kubectl get pod -o wide
4、测试pod访问
curl --head 10.2.83.17
5、更新deployment
kubectl set image deployment/nginx-deployment nginx=nginx:v2 --record
6、查看更新后的deployment
kubectl get deployment -o wide
7、查看更新历史
kubectl rollout history deployment/nginx-deployment
8、查看具体某一个版本的升级历史
kubectl rollout history deployment/nginx-deployment --record
9、快速回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment
10、扩容到5各节点
kubectl scale deployment nginx-deployment --replicas=5

在这里插入图片描述

私有仓库命名:
  • 基于命名空间区分环境与业务,如online-wms
  • 不同命名空间有各自的nginx tomcat镜像,基础镜像作为一个单独的分支
  • 基础镜像命名:openresty-base tomcat-base tag作为基础镜像版本
  • 镜像信息的描述作为每个tag更新的说明
  • 基于基础镜像构建的生产镜像前端应用同一用openresty-ol分支,不同前端代码使用tag作为区分,如openresty-ol:v0.1apph5v0.1,前面的v0.1作为构建时基础镜像的版本,apph5作为业务描述,后面的v0.1作为业务更新的版本
  • 也可不同前端代码不同的分支,但这样分支会很多,查找不方便

问题总结篇

PV-NFS创建时accessModes选择Many,PVC绑定PV失败,选择Once后成功,也可让多个Pod共享访问,控制台只能选择硬盘PV 单台读写

主要看后端存贮,模式一定要一致,用来吐日志NFS有性能瓶颈,推荐file beat,压测NFS性能,容器标准输出到宿主机,

service 绑定deployment时,label选择不正确或少了,导致绑定不成功,访问空白

service 对应Deployment的label
发布蓝鲸调用TKE的API
用NFS方式的war包 TKE一些特性无法实现
本地push镜像到TKE镜像仓库 网速波动

deployment pod的labels 与deployment的labels必须相同
ingress本质就是clb,创建ingress会自动创建一个clb

应用型CLB有url匹配
service ingress 4层7层

pv一旦被pvc绑定后,就被该pvc独占,不能在与其他pvc绑定
pod 减少的时候会不会等待pod内的请求处理完成!

优雅关闭优雅关闭是指在pod准备关闭时,可能还需要做一些处理,比如保存数据等。这期间服务不会接受新的请求。kubernetes提供了优雅关闭的配置terminationGracePeriodSeconds: 60
在给pod发出关闭指令时,k8s将会给应用发送SIGTERM信号,程序只需要捕获SIGTERM信号并做相应处理即可。配置为k8s会等待60秒后关闭。
docker镜像的 STOPSIGNAL SIGQUIT
超过等待时间直接强制杀死POD

业务的代码放在NFS中,更新重启pod即可,镜像在配置文件变更时在pull!

根据不同的路径区分不同的版本

tomcat更改war包和解压文件放到不同目录!
pod的自动扩容频率的间隔时长?

第一次扩 达到即扩容,两次扩的间隔5分钟,两次收缩间隔3分钟
秒杀活动不现实

pod的自动扩容数量为现有pod的2倍,TKE是否同样限制?是否可配置
突然过高并发流量导致pod阻塞,健康检查无法通过导致服务崩溃?

初始pod数量调高 提高系统整体吞吐量,初始pod占用资源调高 提升单个pod的可承受并发量

service对pod的负载规则?能否设置?权重,轮询

轮询

超出指定pod数量的pod实列多长时间会删除和回收?

8个总量,实际占用request的值

Terminating状态的pod会如何处理?时长?

强制删除pod
kubectl delete pod podname --force --grace-period 0 -n namespace
容器内有非空目录(容器运行过程中) 其他情况

node的调度局部最优解和全局最优解:1.12版本后默认未局部最优解

千台node不会出现调度器瓶颈

设置pod的自动扩容的实例数量范围后,pod的数量并未自动扩容到范围的下限数量
容器服务的概览中的集群资源使用量至少需要保持在30%~40%的可用率

此处的资源使用量计算:如果node的内存还剩0.5G 内存0.5G,这样的node有4台,会在资源使用量中生成2G CPU 2G内存,但pod请求的资源某一项超过0.5G则pod不会创建成功,会造成对pod数量的错误计算

健康检测中就绪检测只在容器初始化时检测一次?

在压测时未配置健康检测,只配置了就绪检测,但部分pod发现会重启导致本来就承受不住并发流量的服务崩溃
有检测时间间隔
健康检查失败 重启,存活检查失败 流量不进入

server的Selectors只匹配到deployment不匹配pod?

因通过控制台生成的deployment的label和pod的label相同
label匹配

hpa间隔60S获取一次pod的扩容指标,2~3分钟后扩容的pod恢复到最小数量
hpa获取扩容指标时,有时会并不准确,关闭压测了,并且hpa值已经下降,但下一分钟的hpa值又飙升

在这里插入图片描述

待确定

多个应用放到同一个集群,namespace隔离
CLB目前只能绑定主机
新增NODE,已有POD只等待下次调度,新的POD会分配到新的NODE
海通证券,QQ空间 微视 腾讯视频
非核心交易都已容器化(两年前),秒杀F5限流
前期规划 容器给一个B端
pod同样受所在NODE的安全组限制
日志是filebeat 还是NFS

相关资料地址和网站

Docker官网
DockerHub官网
Kubernetes官网
Kubernetes中文文档
十分钟带你理解Kubernetes核心概念
Kubernetes 编排系统
Docker与虚拟机的简介以及比较

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章