├── .gitignore ├── 1.容器基础 ├── dockerfile │ ├── hello-v1 │ │ ├── Dockerfile │ │ ├── app │ │ │ ├── main.py │ │ │ └── uwsgi.ini │ │ ├── requirements.txt │ │ └── uwsgi.ini │ └── hello-v2 │ │ ├── Dockerfile │ │ ├── app │ │ ├── main.py │ │ └── uwsgi.ini │ │ ├── requirements.txt │ │ └── uwsgi.ini └── 容器基础.md ├── 2.kubernetes基础 └── Kubernetes基础.md ├── 3.服务编排 ├── deployments │ ├── hello-deployment-v2.yaml │ ├── hello-deployment.yaml │ └── hello-replicaset.yaml ├── nginx │ ├── hello-v2.conf │ └── hello.conf ├── pods │ ├── hello-flask-app.yaml │ ├── hello-healthy.yaml │ ├── hello-resources-limit.yaml │ └── hello.yaml └── 服务编排.md ├── 4.服务发现 ├── services │ └── nginx.yaml └── 服务发现.md ├── 5.项目实践 ├── ca.pem ├── project │ ├── auth-deployment.yaml │ ├── auth-service.yaml │ ├── frontend-configmap.yaml │ ├── frontend-deployment.yaml │ ├── frontend-secret.yaml │ ├── frontend-service.yaml │ ├── hello-deployment.yaml │ └── hello-service.yaml └── 项目实践.md ├── README.md ├── config ├── nginx │ ├── frontend.conf │ ├── hello-v2.conf │ └── hello.conf └── tls │ ├── ca-key.pem │ ├── ca.pem │ ├── cert.pem │ ├── key.pem │ ├── ssl-extensions-x509.cnf │ └── update-tls.sh └── docs ├── Kubernetes技术实践(基础篇).pdf ├── configmap.jpg ├── deployment.jpg ├── k8s-master.jpg ├── k8s-node.jpg ├── k8s.jpg ├── micoservice.jpg ├── pod.jpg ├── pods-to-pods.jpg ├── pods-to-service.jpg ├── qq.jpg ├── replicaset.jpg ├── rollout.jpg ├── service-nodeport.jpg ├── service.jpg └── wechat.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | *.swp 4 | *.pyc 5 | !.gitkeep 6 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-stretch 2 | 3 | # Copy requirements.txt and uwsgi.ini file 4 | COPY requirements.txt /tmp/ 5 | COPY uwsgi.ini /etc/uwsgi/ 6 | 7 | # Upgrade pip and install required python packages 8 | RUN pip install -U pip 9 | RUN pip install -r /tmp/requirements.txt 10 | 11 | # Which uWSGI .ini file should be used, to make it customizable 12 | ENV UWSGI_INI /app/uwsgi.ini 13 | 14 | # By default, run 2 processes 15 | ENV UWSGI_CHEAPER 2 16 | 17 | # By default, when on demand, run up to 16 processes 18 | ENV UWSGI_PROCESSES 16 19 | 20 | # Add demo app 21 | COPY ./app /app 22 | WORKDIR /app 23 | 24 | CMD ["/usr/local/bin/uwsgi", "--ini=/etc/uwsgi/uwsgi.ini", "--die-on-term", "--need-app", "--stats-http"] 25 | 26 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v1/app/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | app = Flask(__name__) 3 | 4 | @app.route("/") 5 | def hello(): 6 | return "Oh, Hello World!" 7 | 8 | if __name__ == "__main__": 9 | app.run(host='0.0.0.0', debug=True, port=8000) 10 | 11 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v1/app/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | uid=www-data 3 | gid=www-data 4 | callable=app 5 | wsgi-file=/app/main.py 6 | 7 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v1/requirements.txt: -------------------------------------------------------------------------------- 1 | uwsgi 2 | Flask 3 | 4 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v1/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | socket = /tmp/uwsgi.sock 3 | chown-socket = www-data:www-data 4 | chmod-socket = 666 5 | # Graceful shutdown on SIGTERM, see https://github.com/unbit/uwsgi/issues/849#issuecomment-118869386 6 | hook-master-start = unix_signal:15 gracefully_kill_them_all 7 | stats = 127.0.0.1:9191 8 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-stretch 2 | 3 | # Copy requirements.txt and uwsgi.ini file 4 | COPY requirements.txt /tmp/ 5 | COPY uwsgi.ini /etc/uwsgi/ 6 | 7 | # Upgrade pip and install required python packages 8 | RUN pip install -U pip 9 | RUN pip install -r /tmp/requirements.txt 10 | 11 | # Which uWSGI .ini file should be used, to make it customizable 12 | ENV UWSGI_INI /app/uwsgi.ini 13 | 14 | # By default, run 2 processes 15 | ENV UWSGI_CHEAPER 2 16 | 17 | # By default, when on demand, run up to 16 processes 18 | ENV UWSGI_PROCESSES 16 19 | 20 | # Add demo app 21 | COPY ./app /app 22 | WORKDIR /app 23 | 24 | CMD ["/usr/local/bin/uwsgi", "--ini=/etc/uwsgi/uwsgi.ini", "--die-on-term", "--need-app", "--stats-http"] 25 | 26 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v2/app/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | app = Flask(__name__) 3 | 4 | @app.route("/") 5 | def hello(): 6 | return "Oh, Hello World, Version 2 !!!" 7 | 8 | if __name__ == "__main__": 9 | app.run(host='0.0.0.0', debug=True, port=8000) 10 | 11 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v2/app/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | uid=www-data 3 | gid=www-data 4 | callable=app 5 | wsgi-file=/app/main.py 6 | 7 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v2/requirements.txt: -------------------------------------------------------------------------------- 1 | uwsgi 2 | Flask 3 | 4 | -------------------------------------------------------------------------------- /1.容器基础/dockerfile/hello-v2/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | socket = 127.0.0.1:8000 3 | # Graceful shutdown on SIGTERM, see https://github.com/unbit/uwsgi/issues/849#issuecomment-118869386 4 | hook-master-start = unix_signal:15 gracefully_kill_them_all 5 | stats = 127.0.0.1:9191 6 | 7 | -------------------------------------------------------------------------------- /1.容器基础/容器基础.md: -------------------------------------------------------------------------------- 1 | # 1. 容器基础 2 | 3 | ## 1.1 容器技术 4 | 5 | ### 容器技术的兴起 6 | 7 | 容器技术是怎样兴起的呢?2007年谷歌实现的 cgroups 正式被添加到了Linux内核中,次年 LXC 发布,它是第一个 Linux 容器管理方案。但是从容器技术被提出直到2013年 Docker 的问世,容器技术一直不温不火,直到 Docker 出现后容器相关技术才兴起起来。在 LXC 出现以后为什么没有迅速火热起来呢?LXC 通过内核的 cgroup 和 namespace 特性实现了资源的限制和隔离,但是它并容易使用。随着云计算的发展,平台即服务(PaaS)的概念不断普及,服务部署成了摆在人们面前亟待解决的问题,各个厂商急需找到一套标准化的部署应用的方案。直到2013年,Docker 项目发布后,他对于应用打包的技术创新迅速赢得了开发者的心。开发者通过容器镜像可以非常方便的将自己的应用部署到各 PaaS 平台上。Docker 技术快速在开发者社区传播开来,带来了容器技术的大发展。 8 | 9 | ### 容器解决了什么问题 10 | 11 | 那容器技术到底解决了什么问题呢?就像 Docker 公司声明的 build, ship, run anywhere。Docker 解决的是应用打包、传输和运行的问题,我们可以通过 docker build 创建应用镜像,通过docker push、pull 传输镜像,通过 docker run 运行镜像。Docker 让应用的部署更方便,而容器本身又自带了对资源的限制和隔离能力。有了这些能力我们就可以轻松的将应用部署到 PaaS 平台上并互不影响的运行起来了。 12 | 13 | ### 容器的管理问题 14 | 15 | 随着我们运行的容器项目越来越多,如何对容器进行管理成了摆在开发者面前的问题。Docker 公司也开始意识到这个问题,于是发布了自己的容器编排服务 Docker Compose,随后发布了跨主机的应用编排服务 Docker Swarm。Docker Compose、Docker Swarm、Docker Machine 并称 Docker 公司的编排三剑客。随着 Docker 公司发布自己的容器编排服务,触动了 CoreOS、Google、RedHat 等PaaS 平台公司的利益,为了切割 Docker 公司在容器领域的话语权,Google 公司联和 RedHat 公司以 Google 公司的 Borg 为原型发布了 Kubernetes 容器编排项目。所谓容器编排就是指我们如何将我们的应用容器部署、运行到 PaaS 平台上,对于比较复杂的应用编排,容器编排服务需要帮我们处理应用间的拓扑关系,亲和性和反亲和性,服务发现及服务监控,以及网络、存储方案等等所有问题。而Docker Swarm 和 老牌的 Mesos 在处理复杂应用的编排问题上就捉襟见肘了,于是 Kubernetes 逐渐成为了编排领域的事实标准。 16 | 17 | 我录制的这套视频教程主要以实例的方式讲解如何将我们的应用部署到 Kubernetes 集群上,这是一个实践课程,需要你做在电脑旁边和我一起动手操作。 18 | 19 | ## 1.2 使用容器技术构建应用 20 | 21 | 在讲解应用部署之前,我们先来回顾一下容器相关的知识,因为他是我们接下来编排的主要对象。 22 | 23 | 在日常的运维过程中,我们通常会遇到这样的需求,某个服务需要运行在不同的中间件版本之下,但是使用当前的包管理程序比如yum、apt-get很难在同一个系统中同时安装两个不同版本的中间件。而容器的出现很好的为我们解决了这个问题,通过将我们的代码和中间件一起打包,然后将打包的镜像运行在同一操作系统下,就很简单的解决了我们上面遇到的问题。 24 | 25 | 接下来我们一起打包一个Flask框架的Python Web应用。 26 | 27 | ### 讲解 Dockerfile 文件 28 | 29 | v1版本,通过socket通信 30 | 31 | - 查看应用代码 32 | - 查看应用的uwsgi配置 33 | - 应用依赖的第三方库requirements.txt 34 | - 全局uwsgi配置 35 | - Dockerfile 36 | 37 | v2版本,通过监听端口通信 38 | 39 | - 查看应用代码 40 | - 全局uwsgi配置 41 | 42 | ### 镜像打包 43 | 44 | v1版本,通过socket通信 45 | 46 | docker build -t findsec/hello:v1 . 47 | docker login 48 | docker push findsec/hello:v1 49 | 50 | v2版本,通过监听端口通信 51 | 52 | docker build -t findsec/hello:v2 . 53 | docker login 54 | docker push findsec/hello:v2 55 | 56 | ### 运行容器 57 | 58 | docker run -ti -d --name flask findsec/hello:v1 59 | 60 | ### 进入容器 61 | 62 | docker exec -ti flask bash 63 | 64 | ## 1.3 小结 65 | 66 | 本章中我向你讲述了容器的兴起过程以及容器能做什么以及解决了什么问题。其实容器实际上是一个由 Linux Namespace、Linux Cgroups 和 rootfs 三种技术构建出来的进程的隔离环境。容器的rootfs部分称为“容器镜像”(Container Image),是容器的静态视图;Namespace+Cgroups 构成的隔离环境,这一部分我们称为“容器运行时”(Container Runtime),是容器的动态视图。然后我向你阐述了容器兴起后出现的管理问题,于是出现了容器编排系统。从一个开发者和单一的容器镜像,到无数开发者和庞大的容器集群,容器技术实现了从“容器”到“容器云”的飞跃,标志着它真正得到了市场和生态的认可。 67 | 68 | 接下来我以实例的方式向你讲述了如何打包一个Flask架构的Python Web应用及如何将它运行起来。下一章我将向你讲述 Kubernetes 这个编排工具存在的意义及其架构,它是如何解决容器编排问题,并带领你搭建一个 Kubernetes 集群。 69 | -------------------------------------------------------------------------------- /2.kubernetes基础/Kubernetes基础.md: -------------------------------------------------------------------------------- 1 | # 2. Kubernetes 基础 2 | 3 | ## 2.1 Kubernetes 概述 4 | 5 | ### Kubernetes 是什么 6 | 7 | Kubernetes(k8s)是Google开源由CNCF基金会管理的容器集群管理系统。为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能。Kubernetes 被称为现在化的数据中心操作系统,大家都知道,操作系统是用来管理硬件资源比如 CPU、内存、磁盘、输入输出设备等资源的,并完成对这些资源的调度。而 Kubernetes 是将数据中心里的物理节点作为管理对象,并对物理节点上的资源进行调度完成编排任务。操作系统的另一个特性就是容易扩展,比如,当 GPU 这种硬件出现后,操作系统应该很容扩展去管理这种资源,Kubernetes 作为数据中心操作系统同样也有这样的特性,它也非常容易扩展。 8 | 9 | ## 2.2 Kubernetes 架构 10 | 11 | Kubernetes 的架构从宏观层面的来讲分为两个平面,即控制平面和计算平面,控制平面又称为 Master 节点,Master 节点是整个集群的大脑,负责控制、调度集群资源;计算平面又称为 Node 节点,Node 节点负责运行工作负载,是 Master 节点调度的对象。kubectl 作为 Kubernetes 客户端通过和 Master 节点直接进行通信来控制 Kubernetes 集群。 12 | 13 | ![Kubernetes 架构](https://github.com/findsec-cn/k101/raw/master/docs/k8s.jpg) 14 | 15 | ### 控制节点 16 | 17 | ![Kubernetes Master](https://github.com/findsec-cn/k101/raw/master/docs/k8s-master.jpg) 18 | 19 | - kube-apiserver 对外暴露 Kubernetes API,所有对集群的操作都是通过这组API完成,包括客户端下达应用编排命令给 Kubernetes 集群;kubelet 上报集群资源使用情况;以及各个组件之间的交互都是通过这套 API 完成的。 20 | - kube-controller-manager 负责整个 Kubernetes 的管理工作,保证集群中各种资源处于期望状态,当监控到集群中某个资源状态与期望状态不符时,controller-manager 会触发调度操作。 21 | - kube-scheduler 调度器负责 Kubernetes 集群的具体调度工作,接收来自于controller-manager 触发的调度操作请求,然后根据请求规格、调度约束、整体资源情况进行调度计算,最后将任务发送到目标节点由的kubelet组件执行。 22 | - etcd 是一个高效KV存储系统。在Kubernetes环境中主要用于存储所有需要持久化的数据。 23 | 24 | ### 计算节点 25 | 26 | ![Kubernetes Node](https://github.com/findsec-cn/k101/raw/master/docs/k8s-node.jpg) 27 | 28 | - kubelet 是 Node 节点上核心组件,负责与 docker daemon 进行交互运行 docker 容器;配置网络和数据卷;监控并上报节点资源使用情况。 29 | - kube-proxy 主要负责 Service Endpoint 到 POD 实例的请求转发及负载均衡的规则管理。 30 | 31 | 以上这些组件的运行原理在进阶篇中会详细讲述。 32 | 33 | ## 2.3 Kubernetes 解决了什么问题 34 | 35 | Kubernetes 项目最主要的设计思想是,从更宏观的角度,以统一的方式来定义任务之间的各种关系,更甚至我们可以运用 Kubernetes 扩展能力灵活的自定义任务之间的关系。 36 | 37 | 比如,Kubernetes 项目对容器间的交互关系进行了分类,首先总结出了一类非常常见的“紧密交互”的关系,即:这些应用之间需要直接通过本地文件进行信息交换。 38 | 39 | 在常规环境下,这些应用往往会被直接部署在同一台机器上,通过 Localhost 通信,通过本地磁盘上的文件进行交互。而在 Kubernetes 项目中,这些容器则会被划分为一个“Pod”,Pod 里的容器共享同一个 Network Namespace、同一组数据卷,从而达到高效率交换信息的目的。 40 | 41 | Pod 是 Kubernetes 项目中最基础的一个对象,下一章中我会重中想你介绍 Pod。 42 | 43 | 而对于另外一种更为常见的需求,比如 Web 应用与数据库之间的访问关系,Kubernetes 项目则提供了一种叫作“Service”的服务。像这样的两个应用,往往故意不部署在同一台机器上,这样即使 Web 应用所在的机器宕机了,数据库也完全不受影响。可是,我们知道,对于一个容器来说,它的 IP 地址等信息不是固定的,那么 Web 应用又怎么找到数据库容器的 Pod 呢? 44 | 45 | 所以,Kubernetes 项目的做法是给 Pod 绑定一个 Service 服务,而 Service 服务声明的 IP 地址等信息是“终生不变”的。这个Service 服务的主要作用,就是作为 Pod 的代理入口,从而代替 Pod 对外暴露一个固定的网络地址。 46 | 47 | 除了 Pod、Service 这些基本资源外,Kubernetes 还为我们提供了 Deployment、StatefulSet、Job 等扩展资源,有了这些资源我们就可以轻松的编排我们的服务了,通过这些资源,Kubernetes 为我们提供了应用的水平扩展、滚动升级、自动扩缩容能力,为服务提供了负责均衡、服务监控、服务发现能力。通过这些高级功能以及其灵活的扩展能力使 Kubernetes 逐渐成为了容器编排领域的翘楚。 48 | 49 | ## 2.4 Kubernetes 集群搭建 50 | 51 | ### 使用 Docker CE 自带的 Kubernetes 52 | 53 | 安装 Docker 参考:https://docs.docker.com/install/ 54 | 55 | - Install Docker for Mac 56 | - Install Docker for Windows 57 | 58 | ### 使用 minikube 59 | 60 | #### MacOS 安装 minikube 61 | 62 | - 安装minikube 63 | 64 | brew cask install minikube 65 | 66 | - 安装vm驱动 67 | 68 | curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit \\n&& sudo install -o root -g wheel -m 4755 docker-machine-driver-hyperkit /usr/local/bin/ 69 | 70 | - 启动 minikube(minikube会安装kubernetes需要的组件,这些组件的镜像存储在google的常客中,所有需要能够翻墙才能够安装成功) 71 | 72 | minikube start --vm-driver=hyperkit --memory=4096 --insecure-registry="hub.example.com" --registry-mirror="https://m9sl8pb5.mirror.aliyuncs.com" --docker-opt="bip=172.87.0.1/16" 73 | 74 | 参数介绍: 75 | --vm-driver 使用的虚拟机驱动 76 | --memory 给虚拟机的内存大小 77 | --cpu 给虚拟机的cpu核数,默认是2核 78 | --insecure-registry 指定私有仓库地址 79 | --registry-mirror 指定镜像缓存地址,加快镜像下载速度 80 | --docker-opt 指定docker的启动参数,bip 指定 docker 网桥使用的网段 81 | 82 | - 停止 minikube 83 | 84 | minikube stop 85 | 86 | - 删除集群 87 | 88 | minikube delete 89 | 90 | - 登录虚拟机 91 | 92 | minikube ssh 93 | 94 | #### Windows 安装 minikube 95 | 96 | Windows 安装minikube,需要Windows系统支持Hyper-V,目前 Windows 10 Enterprise, Windows 10 Professional, and Windows 10 Education 支持Hyper-V。安装minikube时,最好命令行使用powershell,并且以管理员身份打开并执行。 97 | 98 | ##### 安装方法 1: 99 | 100 | - 安装 https://chocolatey.org/ 101 | - choco install minikube kubernetes-cli 102 | 103 | ##### 安装方法 2: 104 | 105 | 下载 minikube-installer.exe (https://github.com/kubernetes/minikube/releases/latest)并进行安装。 106 | 107 | 启动前准备(重要) 108 | 109 | - 配置 MINIKUBE_HOME 环境变量及创建目录 110 | - 在 Hyper-V 中为minikube添加虚拟交换机 111 | - 用 chocolatey 安装 OpenSSH(choco install openssh) 112 | 113 | 启动 minikube 114 | 115 | minikube start --vm-driver=hyperv --hyperv-virtual-switch=minikube --memory=4096 --insecure-registry="hub.example.com" --registry-mirror="https://m9sl8pb5.mirror.aliyuncs.com" --docker-opt="bip=172.87.0.1/16" 116 | 117 | ## 2.5 访问 Kubernetes 118 | 119 | ### Dashboard 120 | 121 | #### 访问Dashboard 122 | 123 | 最新版本的 minikube 默认没有安装 Dashboard,执行如下命令 minikube 自动帮我们部署 Dashboard 并启动代理。 124 | 125 | minikube dashboard 126 | 127 | 访问地址: http://localhost:8001/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy/#!/overview?namespace=default 128 | 129 | #### 基本概念 130 | 131 | ##### 集群 132 | 133 | - namespace 逻辑隔离空间,可以在不同的 namespace 里运行不同的微服务,默认使用 default 命名空间 134 | - node 部署集群使用的物理节点,包括控制节点和计算节点 135 | 136 | ##### 工作负载 137 | 138 | - deployment 我们实际部署的服务,所谓部署就是用来描述我们待编排的服务的期望状态的,比如我们这个服务启动的副本数,使用的镜像等等,后面会做详细讲解 139 | 140 | ##### 服务发现 141 | 142 | - service 应用想被其他应用访问,需要先定义一个service,kubernetes自动帮我们解析这个service name,然后其他服务就可以通过service name访问这个服务了 143 | 144 | ##### 配置 145 | 146 | - configmap 定义应用的配置文件,在应用容器启动时挂载到容器中 147 | - secret 同 configmap,定义某些敏感的、需要加密的配置文件,在应用容器启动时挂载到容器中 148 | 149 | ### kubectl 150 | 151 | #### 下载安装 kubectl 152 | 153 | MacOS 安装: 154 | 155 | brew install kubernetes-cli 156 | 157 | Windows 安装: 158 | 159 | choco install kubernetes-cli 160 | cd C:\users\yourusername 161 | mkdir .kube 162 | cd .kube 163 | New-Item config -type file 164 | 165 | #### 配置 kubectl 客户端连接到 kubernetes 集群 166 | 167 | kubectl配置文件 ~/.kube/config 168 | 169 | - clusters 170 | - users 171 | - contexts 172 | 173 | #### 获取集群信息 174 | 175 | kubectl get nodes 176 | kubectl get pods 177 | kubectl get pods -n xxx 178 | 179 | #### 使用命令行部署nginx服务 180 | 181 | kubectl run nginx --image=nginx:1.15 182 | 183 | #### 为nginx创建服务 184 | 185 | kubectl expose deployment nginx --port 80 186 | 187 | #### 获取部署列表 188 | 189 | kubectl get svc 190 | 191 | #### 启动工具容器进行访问测试 192 | 193 | kubectl run -ti busybox --image=busybox --restart=Never -- sh 194 | 195 | #### 测试能否访问服务 196 | 197 | wget http://nginx 198 | 199 | ## 2.6 小结 200 | 201 | 本章中我向你讲述了 Kubernetes 是什么,Kubernetes 的架构,以及它解决了什么问题。在工作中,我们的目标是把我们的应用部署到 Kubernetes 容器云中,在部署应用时,首先遇到了应用间亲密关系的难题,于是就扩展到了 Pod;有了 Pod 之后,我们希望能一次启动多个应用实例,这样就需要 Deployment 这个 Pod 的多实例管理器;而有了这样一组相同的 Pod 后,我们又需要通过一个固定的 IP 地址和端口以负载均衡的方式访问它,于是就有了 Service。在以后的章节中我会给你详细讲解 Pod、Deployment、Service 这些资源对象。 202 | 203 | 最后我演示了如何搭建一个用于测试的 Kubernetes 集群。并通过 Dashboard、kubectl 访问了我们搭建的集群。在下一章我会着重给你讲解如何在 Kubernetes 集群中部署、升级我们的应用。 204 | -------------------------------------------------------------------------------- /3.服务编排/deployments/hello-deployment-v2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hello 5 | labels: 6 | app: hello 7 | spec: 8 | replicas: 2 9 | selector: 10 | matchLabels: 11 | app: hello 12 | template: 13 | metadata: 14 | labels: 15 | app: hello 16 | track: stable 17 | spec: 18 | containers: 19 | - name: nginx 20 | image: nginx:1.15 21 | ports: 22 | - name: http 23 | containerPort: 80 24 | resources: 25 | limits: 26 | cpu: 500m 27 | memory: 0.5Gi 28 | requests: 29 | cpu: 0 30 | memory: 0.5Gi 31 | livenessProbe: 32 | httpGet: 33 | path: / 34 | port: 80 35 | scheme: HTTP 36 | initialDelaySeconds: 5 37 | periodSeconds: 15 38 | timeoutSeconds: 5 39 | readinessProbe: 40 | httpGet: 41 | path: / 42 | port: 80 43 | scheme: HTTP 44 | initialDelaySeconds: 5 45 | periodSeconds: 15 46 | timeoutSeconds: 1 47 | volumeMounts: 48 | - name: "nginx-conf" 49 | mountPath: "/etc/nginx/conf.d" 50 | - name: hello 51 | image: findsec/hello:v2 52 | env: 53 | - name: UWSGI_CHEAPER 54 | value: "5" 55 | ports: 56 | - name: tcp 57 | containerPort: 8000 58 | protocol: TCP 59 | - name: http-stats 60 | containerPort: 9191 61 | resources: 62 | limits: 63 | cpu: 500m 64 | memory: 100Mi 65 | requests: 66 | cpu: 0 67 | memory: 100Mi 68 | volumes: 69 | - name: "nginx-conf" 70 | configMap: 71 | name: "nginx-conf-v2" 72 | items: 73 | - key: "hello-v2.conf" 74 | path: "hello.conf" 75 | -------------------------------------------------------------------------------- /3.服务编排/deployments/hello-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hello 5 | labels: 6 | app: hello 7 | spec: 8 | replicas: 2 9 | selector: 10 | matchLabels: 11 | app: hello 12 | template: 13 | metadata: 14 | labels: 15 | app: hello 16 | track: stable 17 | spec: 18 | containers: 19 | - name: nginx 20 | image: nginx:1.15 21 | ports: 22 | - name: http 23 | containerPort: 80 24 | resources: 25 | limits: 26 | cpu: 500m 27 | memory: 0.5Gi 28 | requests: 29 | cpu: 0 30 | memory: 0.5Gi 31 | livenessProbe: 32 | httpGet: 33 | path: / 34 | port: 80 35 | scheme: HTTP 36 | initialDelaySeconds: 5 37 | periodSeconds: 15 38 | timeoutSeconds: 5 39 | readinessProbe: 40 | httpGet: 41 | path: / 42 | port: 80 43 | scheme: HTTP 44 | initialDelaySeconds: 5 45 | periodSeconds: 15 46 | timeoutSeconds: 1 47 | volumeMounts: 48 | - name: "nginx-conf" 49 | mountPath: "/etc/nginx/conf.d" 50 | - name: "uwsgi-sock" 51 | mountPath: "/tmp" 52 | - name: hello 53 | image: findsec/hello:v1 54 | ports: 55 | - name: http-stats 56 | containerPort: 9191 57 | resources: 58 | limits: 59 | cpu: 500m 60 | memory: 100Mi 61 | requests: 62 | cpu: 0 63 | memory: 100Mi 64 | volumeMounts: 65 | - name: "uwsgi-sock" 66 | mountPath: "/tmp" 67 | volumes: 68 | - name: "uwsgi-sock" 69 | emptyDir: {} 70 | - name: "nginx-conf" 71 | configMap: 72 | name: "nginx-conf" 73 | items: 74 | - key: "hello.conf" 75 | path: "hello.conf" 76 | -------------------------------------------------------------------------------- /3.服务编排/deployments/hello-replicaset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: ReplicaSet 3 | metadata: 4 | name: hello 5 | labels: 6 | app: hello 7 | spec: 8 | replicas: 2 9 | selector: 10 | matchLabels: 11 | app: hello 12 | template: 13 | metadata: 14 | labels: 15 | app: hello 16 | track: stable 17 | spec: 18 | containers: 19 | - name: nginx 20 | image: nginx:1.15 21 | ports: 22 | - name: http 23 | containerPort: 80 24 | resources: 25 | limits: 26 | cpu: 500m 27 | memory: 0.5Gi 28 | requests: 29 | cpu: 0 30 | memory: 0.5Gi 31 | livenessProbe: 32 | httpGet: 33 | path: / 34 | port: 80 35 | scheme: HTTP 36 | initialDelaySeconds: 5 37 | periodSeconds: 15 38 | timeoutSeconds: 5 39 | readinessProbe: 40 | httpGet: 41 | path: / 42 | port: 80 43 | scheme: HTTP 44 | initialDelaySeconds: 5 45 | periodSeconds: 15 46 | timeoutSeconds: 1 47 | volumeMounts: 48 | - name: "nginx-conf" 49 | mountPath: "/etc/nginx/conf.d" 50 | - name: "uwsgi-sock" 51 | mountPath: "/tmp" 52 | - name: hello 53 | image: findsec/hello:v1 54 | ports: 55 | - name: http-stats 56 | containerPort: 9191 57 | resources: 58 | limits: 59 | cpu: 500m 60 | memory: 100Mi 61 | requests: 62 | cpu: 0 63 | memory: 100Mi 64 | volumeMounts: 65 | - name: "uwsgi-sock" 66 | mountPath: "/tmp" 67 | volumes: 68 | - name: "uwsgi-sock" 69 | emptyDir: {} 70 | - name: "nginx-conf" 71 | configMap: 72 | name: "nginx-conf" 73 | items: 74 | - key: "hello.conf" 75 | path: "hello.conf" 76 | -------------------------------------------------------------------------------- /3.服务编排/nginx/hello-v2.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name hello.ku.app; 4 | location / { 5 | include uwsgi_params; 6 | uwsgi_pass 127.0.0.1:8000; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /3.服务编排/nginx/hello.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name hello.example.com; 4 | location / { 5 | include uwsgi_params; 6 | uwsgi_pass unix:///tmp/uwsgi.sock; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /3.服务编排/pods/hello-flask-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: hello 5 | labels: 6 | app: hello 7 | spec: 8 | containers: 9 | - name: nginx 10 | image: nginx:1.15 11 | ports: 12 | - name: http 13 | containerPort: 80 14 | resources: 15 | limits: 16 | cpu: 500m 17 | memory: 0.5Gi 18 | requests: 19 | cpu: 0 20 | memory: 0.5Gi 21 | livenessProbe: 22 | httpGet: 23 | path: / 24 | port: 80 25 | scheme: HTTP 26 | initialDelaySeconds: 5 27 | periodSeconds: 15 28 | timeoutSeconds: 5 29 | readinessProbe: 30 | httpGet: 31 | path: / 32 | port: 80 33 | scheme: HTTP 34 | initialDelaySeconds: 5 35 | periodSeconds: 15 36 | timeoutSeconds: 1 37 | volumeMounts: 38 | - name: "nginx-conf" 39 | mountPath: "/etc/nginx/conf.d" 40 | - name: "uwsgi-sock" 41 | mountPath: "/tmp" 42 | - name: hello 43 | image: findsec/hello:v1 44 | ports: 45 | - name: http-stats 46 | containerPort: 9191 47 | resources: 48 | limits: 49 | cpu: 500m 50 | memory: 100Mi 51 | requests: 52 | cpu: 0 53 | memory: 100Mi 54 | volumeMounts: 55 | - name: "uwsgi-sock" 56 | mountPath: "/tmp" 57 | volumes: 58 | - name: "uwsgi-sock" 59 | emptyDir: {} 60 | - name: "nginx-conf" 61 | configMap: 62 | name: "nginx-conf" 63 | items: 64 | - key: "hello.conf" 65 | path: "hello.conf" 66 | -------------------------------------------------------------------------------- /3.服务编排/pods/hello-healthy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: hello 5 | labels: 6 | app: hello 7 | spec: 8 | containers: 9 | - name: nginx 10 | image: nginx:1.15 11 | ports: 12 | - name: http 13 | containerPort: 80 14 | resources: 15 | limits: 16 | cpu: 1 17 | memory: 2Gi 18 | requests: 19 | cpu: 0 20 | memory: 2Gi 21 | livenessProbe: 22 | tcpSocket: 23 | port: 80 24 | initialDelaySeconds: 5 25 | periodSeconds: 15 26 | timeoutSeconds: 5 27 | readinessProbe: 28 | httpGet: 29 | path: / 30 | port: 80 31 | scheme: HTTP 32 | initialDelaySeconds: 5 33 | periodSeconds: 15 34 | timeoutSeconds: 1 35 | -------------------------------------------------------------------------------- /3.服务编排/pods/hello-resources-limit.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: hello 5 | labels: 6 | app: hello 7 | spec: 8 | containers: 9 | - name: nginx 10 | image: nginx:1.15 11 | ports: 12 | - name: http 13 | containerPort: 80 14 | resources: 15 | limits: 16 | cpu: 1 17 | memory: 2Gi 18 | requests: 19 | cpu: 0 20 | memory: 2Gi 21 | -------------------------------------------------------------------------------- /3.服务编排/pods/hello.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: hello 5 | labels: 6 | app: hello 7 | spec: 8 | containers: 9 | - name: nginx 10 | image: nginx:1.15 11 | ports: 12 | - name: http 13 | containerPort: 80 14 | -------------------------------------------------------------------------------- /3.服务编排/服务编排.md: -------------------------------------------------------------------------------- 1 | # 3. 服务编排 2 | 3 | 上一章中我们部署了一个 Kubernetes 集群,这一章我们的目标是将前面打好 Flask 应用部署到这个集群上。在部署应用之前,我先了解下 Pod 这个概念。 4 | 5 | ## 3.1 Pod 6 | 7 | ### 为什么需要 Pod 8 | 9 | 在上一章中我们提到,Pod 用于解决应用间的紧密交互问题,他只是一个逻辑概念。我们可以将 Pod 和虚拟机做下类比,每个虚拟机里可以运行多个进程,每个 Pod 里也可以运行多个容器,容器的本质就是进程。多个容器之间可以通过 localhost 进行访问,容器间也可以共享数据卷。这一切是如何做到的呢?其实在 Pod 里最先启动的容器并不是我们的应用容器,而是有一个辅助容器叫做 infra(k8s.gcr.io/pause),infra 是 Pod 中最先启动的容器,它负责为 Pod 创建网络和共享存储,而我们的应用容器只是连接了 infra 容器创建的网络和数据卷,这样就达到了共享网络空间和数据卷的目的。 10 | 11 | ![Pod](https://github.com/findsec-cn/k101/raw/master/docs/pod.jpg) 12 | 13 | - 共享网络空间 14 | - 共享 Volumes 15 | - 每个 Pod 一个 IP 地址 16 | 17 | ### ConfigMap 18 | 19 | 有些配置我们并不会打包到容器里,因为它们变动比较频繁,我们通常在容器启动的时候,将它们挂载到容器里。Kubernetes 为了应对这种需求就有了 ConfigMap 这种资源;有些配置文件里有敏感信息,需要对这些信息进行加密,为了应对这种需求就有了 Secret 这种资源。 20 | 21 | 创建 ConfigMap 的步骤如下: 22 | 23 | - 编写 ConfigMap 配置 24 | - 通过 kubectl 客户端提交给 Kubernetes 集群 25 | - Kubernetes API Server 收到请求后将 配置存储到 etcd 中 26 | - 容器启动时,kubelet 发请求给 API Server,将 ConfigMap 挂在到容器里 27 | 28 | ### 创建 nginx 配置 29 | 30 | ![ConfigMap](https://github.com/findsec-cn/k101/raw/master/docs/configmap.jpg) 31 | 32 | kubectl create configmap nginx-conf --from-file=nginx/hello.conf 33 | 34 | 在部署我们的 Flask 应用之前,我先部署一个 Nginx 服务。因为这个 Flask 应用是用 uwsgi 启动的,为了应对大流量访问,通常需要在前面部署一个 Nginx 代理服务。 35 | 36 | kubectl create -f pods/hello.yaml 37 | kubectl get pods 38 | 39 | 可以看到我们的 hello pod 已经启动了,但是如果 Nginx 占用大量的内存或CPU,会影响到这台物理机上启动的其他容器,所有我们要对这个 Nginx 容器做资源限制。 40 | 41 | kubectl replace --force -f pods/hello-resources-limit.yaml 42 | kubectl edit pods 43 | 44 | 我们给 Nginx 服务加了资源限制,但是当这个服务出现问题时,我们怎么检测到这个故障,并给他自动恢复呢?这时候就需要对这个服务进行监控了。 45 | 46 | kubectl replace --force -f pods/hello-healthy.yaml 47 | kubectl edit pods 48 | 49 | 我们可以通过 kubectl describe 看到 pod 的具体状态。 50 | 51 | kubectl describe pod hello 52 | 53 | Pod的状态Status: 54 | 55 | - Pending:Pod 的配置已经被 API Server 存储到 etcd 中,但是此Pod因为某种原因不能被创建 56 | - Running:Pod 已经被调度成功并且绑定到了某个节点上,容器创建成功并开始运行 57 | - Succeeded:Pod 都正常运行完毕并已退出,这种状态一般在一次性任务中比较常见 58 | - Faild:Pod 里至少有一个容器运行不正常(非0状态退出),需要查找Pod失败原因 59 | - Unknown:Pod 的状态不能持续的被 kubelet 汇报给 API Server,可能是主节点也 kubelet通信问题 60 | 61 | 细分状态 Conditions: 62 | 63 | - PodScheduled Pod 是否已经被调度,即给他分配了物理节点 64 | - ContainersReady 容器是否已经处于 Ready 状态 65 | - Ready Pod 是否应 Running 并且能够对外提供服务 66 | - Initialized 是否完成了容器初始化操作 67 | - Unschedulable 可能资源不足导致调度失败 68 | 69 | 我们对 Nginx 容器做资源限制,并且进行了监控检查,我们的 Nginx 服务就配置完成了,那我们改如何让他代理我们的 Flask 应用容器呢?答案就是讲 Nginx 容器和 Flask 应用容器运行在同一个Pod 中,两个容器通过 socket 文件进行交互。 70 | 71 | ### 部署 Flask 应用 72 | 73 | kubectl replace --force -f pods/hello-flask-app.yaml 74 | kubectl get pods hello 75 | 76 | ### 访问测试 77 | 78 | kubectl port-forward hello 10080:80 79 | curl http://127.0.0.1:10080 80 | 81 | ### 查看容器日志 82 | 83 | kubectl logs -c nginx hello 84 | kubectl logs -c hello hello 85 | 86 | ### 登录容器 87 | 88 | kubectl exec -ti hello -c hello bash 89 | 90 | 至此,我们运行了一个 Flask 应用,并在前面给他加个一个 Nginx 代理。但你有没有想过,当我们部署的这个 pod 挂了或者突然访问量加大了,会出现什么问题?如果 pod 挂了,那么服务就不能正常访问了,那怎么解决这个问题?多起几个pod,某一个挂了,其他仍有可以提供访问;如果访问量加大,同样也可以启动多个 pod 进行分流。 91 | 92 | 那我们应该如何启动多个 pod 呢? 答案就是 ReplicaSet。 93 | 94 | ## 3.2 ReplicaSet 95 | 96 | ReplicaSet 这个控制器就是为了启动多个 Pod 副本设计的。我们通过 ReplicaSet 重新部署这个应用。 97 | 98 | ![ReplicaSet](https://github.com/findsec-cn/k101/raw/master/docs/replicaset.jpg) 99 | 100 | 在部署前,我们可以先把原先部署的 Pod 清理掉。 101 | 102 | kubectl delete -f pods/hello-flask-app.yaml 103 | 104 | 然后通过 ReplicaSet 重新部署这个 Flask 应用。 105 | 106 | kubectl apply -f deployments/hello-replicaset.yaml 107 | kubectl get rs 108 | 109 | kubectl describe rs hello 110 | 111 | 通过 ReplicaSet 我们实现了启动多个 Pod 副本的目的。现在我们的 Flask 应用有了新版本,我想升级它,但又不能影响用户的访问,我该怎么做?滚动升级这个特性我们改如何实现?答案就是 Deployment。 112 | 113 | 我们可以先删除rs资源,然后用 Deployment 重新部署这个应用。 114 | 115 | kubectl delete -f deployments/hello-replicaset.yaml 116 | 117 | ## 3.3 Deployment 118 | 119 | 一个 ReplicaSet 对象,其实就是由副本数目的定义和一个 Pod 模板组成的。不难发现,它的定义其实是 Deployment 的一个子集。Deployment 控制器实际操纵的正是这样的 ReplicaSet 对象,而不是 Pod 对象。 120 | 121 | ![Deployment](https://github.com/findsec-cn/k101/raw/master/docs/deployment.jpg) 122 | 123 | Deployment 与 ReplicaSet 以及 Pod 的关系是怎样的呢? 124 | Deployment 与它的 ReplicaSet 以及 Pod 的关系,实际上是一种“层层控制”的关系。ReplicaSet 负责通过“控制器模式”,保证系统中 Pod 的个数永远等于指定的个数(比如,3 个)。这也正是 Deployment 只允许容器的 restartPolicy=Always 的主要原因:只有在容器能保证自己始终是 Running 状态的前提下,ReplicaSet 调整 Pod 的个数才有意义。而在此基础上,Deployment 同样通过“控制器模式”,来操作 ReplicaSet 的个数和属性,进而实现“水平扩展 / 收缩”和“滚动更新”这两个编排动作。 125 | 126 | ![Rollout](https://github.com/findsec-cn/k101/raw/master/docs/rollout.jpg) 127 | 128 | 通过 Deployment 重新部署 Flask 应用: 129 | 130 | kubectl apply -f deployments/hello-deployment.yaml 131 | kubectl get deployment 132 | kubectl describe deployment/hello 133 | 134 | 升级Flask 应用,查看滚动升级的过程: 135 | 136 | kubectl apply -f deployments/hello-deployment.yaml 137 | kubectl get deployment 138 | 139 | ## 3.4 小结 140 | 141 | 本章从 Kubernetes 的最小单位 Pod 开始讲起,为了解决服务编排时两个服务间亲密关系,Kubernetes 引入了 Pod 这个逻辑概念,定义在同一个 Pod 里的容器共享网络空间、存储卷,并且一起被调度。我们解决了服务间的亲密关系后还需要为服务运行多个副本同时对外提供服务,于是引入了 ReplicaSet 这个控制器。为了解决服务滚动升级的问题,引入了 Deployment 这个控制 ReplicaSet 的控制器。通过 Deployment 这个控制器我们就能够轻松的将我们应用部署到 Kubernetes 集群上,并对他进行滚动升级。那我们怎么访问刚刚我们部署的服务呢?下一章我讲向你讲述如何暴露我们刚刚部署的服务供其他服务访问。 142 | -------------------------------------------------------------------------------- /4.服务发现/services/nginx.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: hello 5 | spec: 6 | selector: 7 | app: hello 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: 80 12 | targetPort: 80 13 | nodePort: 30080 14 | type: NodePort -------------------------------------------------------------------------------- /4.服务发现/服务发现.md: -------------------------------------------------------------------------------- 1 | # 服务发现 2 | 3 | 上一章中我们通过Deployment部署了一个Flask应用,并且通过登录到容器内部验证了服务是否能够正常访问。那我们该如何对外暴露应用供其他服务访问呢?以及我们该如何在集群外部访问集群内部的服务呢?本章带领大家一起去探索。 4 | 5 | ## 4.1 Service 6 | 7 | ### 为什么需要 Service 8 | 9 | 集群中的每一个 Pod 都可以通过 Pod IP 直接访问,但是正如我们所看到的,Kubernetes 中的 Pod 是有生命周期的,尤其是被 ReplicaSet、Deployment 等对象管理的 Pod,随时都有可能被销毁和重建。这就会出现一个问题,当 Kuberentes 集群中的一些 Pod 需要为另外的一些 Pod 提供服务时,我们如何为这组 Pod 建立一个抽象让另一组 Pod 找到它。这个抽象在 Kubernetes 中其实就是 Service,每一个 Service 都是一组 Pod 的逻辑集合和访问方式的抽象。即 Service 至少帮我们解决了如下问题: 10 | 11 | - 对外暴露部署的应用 12 | - 为一组 Pod 提供负载均衡功能 13 | - 监控 Pod 中启动容器的健康状况,不健康则踢除 14 | - 将服务名注册到 DNS 中去 15 | 16 | ![Pods to Pods](https://github.com/findsec-cn/k101/raw/master/docs/pods-to-pods.jpg) 17 | 18 | ### 如何暴露 Service 19 | 20 | Kubernetes 中的 Service 对象将一组 Pod 以统一的形式对外暴露成一个服务,它利用运行在内核空间的 iptables 或 ipvs 高效地转发来自节点内部和外部的流量。 21 | 22 | ![Pods to Service](https://github.com/findsec-cn/k101/raw/master/docs/pods-to-service.jpg) 23 | 24 | 对于每一个 Service,会在节点上添加 iptables 规则,通过 iptables 或 ipvs 将流量转发到后端的 Pod 进行处理。 25 | 26 | ![Service](https://github.com/findsec-cn/k101/raw/master/docs/service.jpg) 27 | 28 | 在集群的内部我们可以通过这个 ClusterIP 访问这组 Pod 提供的服务,那如何在集群外部访问这个服务呢?这里最常用的一种方式就是:NodePort。在这个 Service 的定义里,通过声明它的类型为 type=NodePort。当我们配置了 NodePort 这种服务类型后,Kubernetes 会在每个物理节点上生成 iptables 规则,将相应端口的流量导入到集群内部,这样我们就可以在集群外部访问到这个服务了。另外一种类型叫 LoadBalancer,这个适用于公有云上的 Kubernetes 对外暴露服务。 29 | 30 | ![NodePort](https://github.com/findsec-cn/k101/raw/master/docs/service-nodeport.jpg) 31 | 32 | ### 服务发现 33 | 34 | 我们通过 Service 这个抽象对外暴露服务,但还有一个问题,在 Kubernetes 集群中,A 服务访问 B 服务,如果 B 服务是一个还未部署的服务,这时,我们是不知道 B 服务的 ClusterIP 是什么的?那我在编写 A 服务的代码时,如何描述 B 服务呢?其实,我们可以给这个服务定义一个名字,当 B 服务部署时自动解析这个名字就可以了。这就是 Kubernetes 内部的服务发现机制。Service 被分配了 ClusterIP 后,还会将自己的服务名注册到 DNS 中,这样其他服务就可以通过这个服务名访问到这个服务了。如果 A、B 两个服务在相同的命名空间,那么他们通过 svc_name 就可以相互访问了(如上例:hello),如果是在不同的命名空间还需要加上命名空间的名字,如 svc_name.namespace(如上例:hello.default),或者使用完整域名去访问,一般是 svc_name.namespace.svc.cluster.local(如上例:hello.default.svc.cluster.local)。 35 | 36 | ### 如何配置 Service 37 | 38 | #### 部署 Service 39 | 40 | kubectl apply -f services/nginx.yaml 41 | 42 | #### 获取 Service 的 Endpoint 43 | 44 | kubectl get endpoints hello 45 | 46 | #### 获取 Service 47 | 48 | kubectl get svc hello 49 | 50 | #### 访问 Service 51 | 52 | minikube ssh 53 | curl https://127.0.0.1:30080 54 | 55 | 56 | ## 4.2 小结 57 | 58 | 本章服务发现相关的知识,我向你讲解了为什么需要 Service 这个资源,以及如何将 Service 暴露出来。Service 为服务间的相互访问提供了一个固定的端点,也为多个 Pod 提供了负载均衡能力,并且他能够监控 Pod 内容器的健康状况,当容器出错时将其从负载均衡后面摘除。另外 Service 将服务名注册到 DNS 中,以便其他服务发现此服务。 59 | 60 | 下一章是一节实践课,我们利用前面学到的知识,将一个微服务部署到 Kubernetes 集群中。 61 | -------------------------------------------------------------------------------- /5.项目实践/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC/TCCAeWgAwIBAgIJAOqHnLeBjLOhMA0GCSqGSIb3DQEBCwUAMBUxEzARBgNV 3 | BAoMCkt1YmVybmV0ZXMwHhcNMTcxMjI4MDA0NzEyWhcNMjcwOTI3MDA0NzEyWjAV 4 | MRMwEQYDVQQKDApLdWJlcm5ldGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 5 | CgKCAQEAwYxTGfCJQsegBeE8n4QV1aowpU6FcSYruK7iH8PVsNUWCg/zfOiG5YDU 6 | 7IC9TwZHM2GnAVRHxTnOqyjUGig6sb9CLmDqS4AkZWaW+wmtul8ZyMiU5jDDM/M1 7 | tTbojuquK8loTlmZ8eITFg4QDwmovZQyMHRfB3pS/FevnrIRGLnPbpawH+XGw5oZ 8 | kNLzj63/AElrIXrOIbHv+flAscFzLekwnCe623LYURmMslnNXkgTMpvxKpCGBRJ/ 9 | R2vGsl/5uma4o+IhfppU/Hx16uBTLVxbFPL9BxQTjLCzcP+a37JTaCdsWo9SafhQ 10 | Oea0xkbWQJwyv7tEtk/l/A4n7MKDbwIDAQABo1AwTjAdBgNVHQ4EFgQUEdeeHGX3 11 | JLMqY/3onHTddbH4CPIwHwYDVR0jBBgwFoAUEdeeHGX3JLMqY/3onHTddbH4CPIw 12 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAp2VEkGpdPc0G8CFJ4Wp3 13 | BvV0zQqKz/3YYkbF9ADXiOzW+brysBlNsZuhoWjUHh7y+bjRVaFZfEYugA9OXqID 14 | r0zdd7AoiA0lnfI1LPsM08lnGj68O1m5IuvupkpPEIQfLIJSnAQTyLY7VV1OvxS6 15 | xnHYuf6UTX2kRqFSJ/RcGZY/9OXoDTQ9m+dQXHgYXM4SvCk6ePNPT7mTpaDbrze9 16 | gAQsisj/pS5AWnADwAasDr5xcRJ63DACshXlMvZ+cs5rkhyJj64FjU40H+fm2kFW 17 | vs4pxkVq/w9QkzbwncfWOErOmtjZWrNWqmgBAwovFTgWCqz30ZY8iBNg66Ody3R7 18 | 8Q== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /5.项目实践/project/auth-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: auth 5 | spec: 6 | replicas: 1 7 | template: 8 | metadata: 9 | labels: 10 | app: auth 11 | track: stable 12 | spec: 13 | containers: 14 | - name: auth 15 | image: "findsec/example-auth:1.0.0" 16 | ports: 17 | - name: http 18 | containerPort: 80 19 | - name: health 20 | containerPort: 81 21 | resources: 22 | limits: 23 | cpu: "0.2" 24 | memory: "10Mi" 25 | livenessProbe: 26 | httpGet: 27 | path: /healthz 28 | port: 81 29 | scheme: HTTP 30 | initialDelaySeconds: 5 31 | periodSeconds: 15 32 | timeoutSeconds: 5 33 | readinessProbe: 34 | httpGet: 35 | path: /readiness 36 | port: 81 37 | scheme: HTTP 38 | initialDelaySeconds: 5 39 | timeoutSeconds: 1 40 | -------------------------------------------------------------------------------- /5.项目实践/project/auth-service.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: "auth" 5 | spec: 6 | selector: 7 | app: "auth" 8 | ports: 9 | - protocol: "TCP" 10 | port: 80 11 | targetPort: 80 12 | -------------------------------------------------------------------------------- /5.项目实践/project/frontend-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: nginx-frontend-conf 5 | labels: 6 | app: frontend 7 | track: stable 8 | data: 9 | frontend.conf: |- 10 | upstream hello { 11 | server hello.default.svc.cluster.local; 12 | } 13 | 14 | upstream auth { 15 | server auth.default.svc.cluster.local; 16 | } 17 | 18 | server { 19 | listen 443; 20 | ssl on; 21 | 22 | ssl_certificate /etc/tls/cert.pem; 23 | ssl_certificate_key /etc/tls/key.pem; 24 | 25 | location / { 26 | proxy_pass http://hello; 27 | } 28 | 29 | location /login { 30 | proxy_pass http://auth; 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /5.项目实践/project/frontend-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: frontend 5 | spec: 6 | replicas: 1 7 | template: 8 | metadata: 9 | labels: 10 | app: frontend 11 | track: stable 12 | spec: 13 | containers: 14 | - name: nginx 15 | image: "nginx:1.15" 16 | lifecycle: 17 | preStop: 18 | exec: 19 | command: ["/usr/sbin/nginx","-s","quit"] 20 | volumeMounts: 21 | - name: "nginx-frontend-conf" 22 | mountPath: "/etc/nginx/conf.d" 23 | - name: "tls-certs" 24 | mountPath: "/etc/tls" 25 | resources: 26 | limits: 27 | cpu: "0.5" 28 | memory: "1Gi" 29 | volumes: 30 | - name: "tls-certs" 31 | secret: 32 | secretName: "tls-certs" 33 | - name: "nginx-frontend-conf" 34 | configMap: 35 | name: "nginx-frontend-conf" 36 | items: 37 | - key: "frontend.conf" 38 | path: "frontend.conf" 39 | -------------------------------------------------------------------------------- /5.项目实践/project/frontend-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: tls-certs 5 | labels: 6 | app: frontend 7 | track: stable 8 | type: Opaque 9 | data: 10 | cert.pem: |- 11 | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURjVENDQWxtZ0F3SUJBZ0lKQVBtM2tFZmpQOGRITUEwR0NTcUdTSWIzRFFFQkN3VUFNQlV4RXpBUkJnTlYKQkFvTUNrdDFZbVZ5Ym1WMFpYTXdIaGNOTVRjeE1qSTRNREEwTnpFeVdoY05NamN3T1RJM01EQTBOekV5V2pBdApNUk13RVFZRFZRUUtEQXBMZFdKbGNtNWxkR1Z6TVJZd0ZBWURWUVFEREEwcUxtVjRZVzF3YkdVdVkyOXRNSUlCCklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFsTFFvS2Y1SG04UzJXVkY3QUduQnV4bGoKNGF1dUxjUEpWaCt6ZVFaTzRMZjVJYXRKQkJubUx6V3p2eGJwbzU4MlJJUVZQWE9WcjJBeDhXTURuUGZpUjNHcgpGZjhRZy9TaFFjSzBmL1QzTTJrMUhXTktqckdmOU54eXVFZW0xN1Vic3MyRjRpMGhNb3NmS3kyWHNSUXdlb3J4CndtZk5hYytuMndPODRzNEZTRkQ5ck0yc1RSUDJSRkxjdXViNmplZEQrd0dobUdHTllYYy9qVUdITVZCRGZsbEoKZEUvNkdVV2dkeldGZEdaRTZ6eERncG5mMk9HTFVFSjV0c0M4UnR4aVFpQUFyODNKR0p1Yy9hOFBFZlZYK2ZkdgpDNHZnWHl2Smhod2pnR1VyUlRPc0pDMk9tSXJueHNzWkRMRDU2VkR3VW4yM2NJNGk0b3ZVWW4rWXZ6enhkd0lECkFRQUJvNEdyTUlHb01BNEdBMVVkRHdFQi93UUVBd0lGb0RBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3REFZRFZSMFRBUUgvQkFJd0FEQWRCZ05WSFE0RUZnUVVQNHNpVVVhaTAvZW1kdmdObzBXdAp1dlBQT2dBd0h3WURWUjBqQkJnd0ZvQVVFZGVlSEdYM0pMTXFZLzNvbkhUZGRiSDRDUEl3S1FZRFZSMFJCQ0l3CklJY0Vmd0FBQVlJSmJHOWpZV3hvYjNOMGdnMHFMbVY0WVcxd2JHVXVZMjl0TUEwR0NTcUdTSWIzRFFFQkN3VUEKQTRJQkFRQi9QajdjMjNoRmFGZUl2VzNVTlBzMHpSUTFadTBVRDNPcGI1bUdsMU5jMFd4UUJnTU05Q0NidWkreApDeU1tMW0rT2VaVXJoUk9ZdGtnaEhDL2doSnM2bVg5ZWZBVzlQdXp6MndoSzdoRHFMWS9BSmtUQkNLNnN5T2UxCmhzK3NrbXQ2VjNqbWcybE1DVmtJUTUyNnVibmRZa0pMUmF5MEFkcGVMZW9rTXlwUHNqWVJOaXV3N21wRlFpbXoKVlFnQ2xPd2ZCODJXTUdrYWl0Z1Uxd3JFekJCNVhUb2RyZnY1MWVVWnZqNjZaS243dm84Q2hHZ0hFVCs3MUNtLwpWeHBSNy9QbHhtSjdJSGhabDlUbVZPOHFqTnFobExSc21ER2VuUjZUVTdiSTBwTmErNmJ4N3BobGpJQWg3K0h1CkVxM080bTBRVVJnelArVjRsSGdzdDc1MjIzcmsKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= 12 | key.pem: |- 13 | LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBbExRb0tmNUhtOFMyV1ZGN0FHbkJ1eGxqNGF1dUxjUEpWaCt6ZVFaTzRMZjVJYXRKCkJCbm1Meld6dnhicG81ODJSSVFWUFhPVnIyQXg4V01EblBmaVIzR3JGZjhRZy9TaFFjSzBmL1QzTTJrMUhXTksKanJHZjlOeHl1RWVtMTdVYnNzMkY0aTBoTW9zZkt5MlhzUlF3ZW9yeHdtZk5hYytuMndPODRzNEZTRkQ5ck0ycwpUUlAyUkZMY3V1YjZqZWREK3dHaG1HR05ZWGMvalVHSE1WQkRmbGxKZEUvNkdVV2dkeldGZEdaRTZ6eERncG5mCjJPR0xVRUo1dHNDOFJ0eGlRaUFBcjgzSkdKdWMvYThQRWZWWCtmZHZDNHZnWHl2Smhod2pnR1VyUlRPc0pDMk8KbUlybnhzc1pETEQ1NlZEd1VuMjNjSTRpNG92VVluK1l2enp4ZHdJREFRQUJBb0lCQUZxcXlmNW91eEtmeXlzRQpna0hMT2NNeGhQUDQ4SmVZMDY2K1gzaUFQeUhIS3BDNzFpWTVBRjl5bCtrQU9HNTZTZVZXdjNpYmUvM1ZZajR5CngrWXlRZmFidU53TmkrMVkvK1dQcU95SDJSMnduU0VSQkVtaXhjdlBpZWNRVVFzZXN3ZS9SazJVaExSRG5UcC8KYndrYUxVRGFiUFBDeEwwcVRzYzhMVFFBdDduU01oYVZoM0pEQlpwR3ZLUjJDZ0ZEVm9UdTRQQm5STmxtZnU4bwpkU0NqZmttaFcrVVpnaXVMczhRS1RSZGhVYTlGU1h2R1ZSaWxVckZ1WExsQzN5VERsK1ZEZXdzRGpmUzJBVUF3CjZGZWJRREpWZVZsVytmdlFsMmQraVhvbkQ1Rm1WVkx1bHJNZmhXZVk5aXB0TlcvV28rQThKWHFSRURveU1tQ3gKK1RoMHpORUNnWUVBeGM2eGI5U00rT0tRVzh2RlJaYjNtSTlYZFRhck1HTXV5SUJ0Z1JQbGh2eEYxQlEyeHJ1MQprU3d1amh2a0REdVdEWURwcE50QXZNWGVITFFUeElva0dqN0lxZlpyMEFTVWg5MDJDTzE5Sk0rWVpLMHh0Skd3CmlSN0hpbXlXaXVib2NBSFFZU2ZDWisvdExYdEd6OEFQTTU2RGlLNk1JN1Fmc2tEY3lJSzVuUjhDZ1lFQXdITmMKTVZtd2d2Zzl6N1UrZE9KWmh0WmJibHJPQThJaTBXS0tCclhKYUJ0eDhHNEdFMGZ5b3JXM0lIQ0M3cUQ4SEozeQpIQ2YwSW9UNlozU2dIUklSMzNjWHRPK2FvNlVjYkV5OEZhTDdqRzVOWEVQUWErT09CeDg1bE9iN3ZLTTNZNTIvCnBITm03aTNKOElzZS9heDAxTkZ5aE43TzZZTStISHptMVIyTXlLa0NnWUVBb2lyM1cwaDFucUlZV2Jtd2JJSDkKVVN6TE5jUnhDb1YxMkZrNTdXWERlaXdlajJWWEZ3elRLVWFBa0c4YlFsQWpqOFNOU0dPY0ttZEoxbHhvREd4NApkcS9jVVVNK1ZsYzY4andRVGJkdUxweW5RbnFmVW50U3NNZjBMVzhpNkpPd0lndktxNnd0L0lvOTkxaW0wREdVCkJPekN4MjdhWTNjTHVWYmw2dGtKbFY4Q2dZQk82UDVNWGZJNlFYOVd3NEl3ZXY4cWdvcEszWURMbWJhZEZFSjAKTGVXL2drRmR6RDlCZUtiTWdLWHQ3elJBbEZITGloZlQ0NjMrMlhlekkrYmpCSjIvZXgyRld4bVZNQVpQZ2NjOQpOKzdjemYxNmIzUHVTUWZiYzdvd2krVjhtNUFDa0pRYjRoVzZZNXdCdlltZmlpNzlkRVA0cDBOQURFaFRkZ05RCkx5V2l3UUtCZ1FDNkUyMGl1RjQ4Y1dKT1Rzdm9ZNHFYTVlKZHpIZjRuZlVJaWdRaGJXcHF5Wkhvd0tzYnJyWlMKcnhhSkt3V0kwQS9NNWd3SzA1NldkM1JabmNFeTlYZ05LRS9HQlduZllGN09hWjNQQUgrTUpYNG9GVUpaKzA0cgpGMlRhcloyeUZqdEx3bTg4ZEx1cDF5TzJXQ3ZwVlRySEcvTGRMckIvSG45bkFGWnRrY1R6d0E9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= 14 | 15 | -------------------------------------------------------------------------------- /5.项目实践/project/frontend-service.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: "frontend" 5 | spec: 6 | selector: 7 | app: "frontend" 8 | ports: 9 | - protocol: "TCP" 10 | port: 443 11 | targetPort: 443 12 | nodePort: 30443 13 | type: NodePort 14 | 15 | -------------------------------------------------------------------------------- /5.项目实践/project/hello-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: hello 5 | spec: 6 | replicas: 1 7 | template: 8 | metadata: 9 | labels: 10 | app: hello 11 | track: stable 12 | spec: 13 | containers: 14 | - name: hello 15 | image: "findsec/example-hello:1.0.0" 16 | ports: 17 | - name: http 18 | containerPort: 80 19 | - name: health 20 | containerPort: 81 21 | resources: 22 | limits: 23 | cpu: "0.2" 24 | memory: "10Mi" 25 | livenessProbe: 26 | httpGet: 27 | path: /healthz 28 | port: 81 29 | scheme: HTTP 30 | initialDelaySeconds: 10 31 | periodSeconds: 15 32 | timeoutSeconds: 5 33 | readinessProbe: 34 | httpGet: 35 | path: /readiness 36 | port: 81 37 | scheme: HTTP 38 | initialDelaySeconds: 10 39 | timeoutSeconds: 5 40 | -------------------------------------------------------------------------------- /5.项目实践/project/hello-service.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: "hello" 5 | spec: 6 | selector: 7 | app: "hello" 8 | ports: 9 | - protocol: "TCP" 10 | port: 80 11 | targetPort: 80 12 | -------------------------------------------------------------------------------- /5.项目实践/项目实践.md: -------------------------------------------------------------------------------- 1 | # 项目实践 2 | 3 | 本次课程是一节实践课,在这次课程中,我们利用前面学到的知识部署两个微服务到 Kubernetes 集群中。主要是带大家一起回归一下 deployment、configmap、secret、service 这些资源如何配合使用。 4 | 5 | 本次部署微服务如下图所示: 6 | 7 | ![微服务架构](https://github.com/findsec-cn/k101/raw/master/docs/micoservice.jpg) 8 | 9 | 这次部署的服务是有两个微服务和一个代理服务组成的,auth 这个微服务提供了认证功能,我们通过访问这个服务来获取请求其他接口的 Token,然后使用这个 Token 去访问 hello 这个微服务,这个微服务验证这个 Token,如果验证成功则接口返回正常响应,否则返回验证失败。frontend 为 auth 和 hello 这两个服务提供代理服务,根据 url 路由用户请求到两个微服务上。 10 | 11 | ## 5.1 项目部署 12 | 13 | ### 部署 14 | 15 | kubectl apply -f project/ 16 | 17 | ### 获取pods 18 | 19 | kubectl get pods 20 | NAME READY STATUS RESTARTS AGE 21 | auth-7fd44dbc5b-klz9k 1/1 Running 0 108s 22 | frontend-84794db478-2wqrk 1/1 Running 0 108s 23 | hello-9944bc998-wgq88 1/1 Running 0 107s 24 | 25 | ### 登录虚拟机 26 | 27 | minikube ssh 28 | 29 | ## 拷贝ca.pem到虚拟机上 30 | 31 | ### 访问非授权接口返回成功 32 | 33 | curl --cacert ./ca.pem https://127.0.0.1:30443/hello 34 | {"message":"Hello"} 35 | 36 | ### 访问非授权接口返回失败 37 | 38 | curl --cacert ./ca.pem https://127.0.0.1:30443/secure 39 | authorization failed 40 | 41 | ### 获取接口JWT Token 42 | 43 | curl --cacert ./ca.pem -u user https://127.0.0.1:30443/login 44 | Enter host password for user 'user':password 45 | {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJleHAiOjE1NDcyNzg4NjcsImlhdCI6MTU0NzAxOTY2NywiaXNzIjoiYXV0aC5zZXJ2aWNlIiwic3ViIjoidXNlciJ9.bT3flMe_VywoFkGCFt08Tw0fxytKZblj8lBHNVLYC6U"} 46 | 47 | ### 使用Token访问接口成功返回 48 | 49 | curl --cacert ./ca.pem -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJleHAiOjE1NDcyNzg4NjcsImlhdCI6MTU0NzAxOTY2NywiaXNzIjoiYXV0aC5zZXJ2aWNlIiwic3ViIjoidXNlciJ9.bT3flMe_VywoFkGCFt08Tw0fxytKZblj8lBHNVLYC6U' https://127.0.0.1:30443/secure 50 | 51 | ## 5.2 小结 52 | 53 | Kubernetes 技术实践--基础篇到此就讲完了,在基础篇里我给你讲述如何将应用打包成镜像并上传到公有仓库;如何从公有仓库下载并启动这个镜像;并向你讲述了 Kubernetes 架构及各个组件的作用;如何搭建测试目的的 Kubernetes 集群;如何将应用部署到集群上,并对它进行滚动升级。基础篇的目的是带领大家部署一个服务到 Kubernetes 集群上,在接下来的进阶篇中主要给大家介绍 Kubernetes 如何在企业环境中落地,主要涉及 Kubernetes 高可用集群的搭建;企业级的私有仓库的部署;使用 helm 部署应用;通过 CI/CD 管道自动化部署过程;还会向大家讲述网络该如何选型;持久换存储该如何部署、使用;集群及部署在上面的服务该如何监控、报警;日志该如何收集、分析;还会涉及 Service Mesh 服务网格的一些知识,比如:如何进行流量路由,如何进行服务降级,如何进行分布式链路追踪等等。大家可以加入QQ 群(774607973),我们会第一时间在群里发布进阶篇相关的信息,敬请期待!希望大家早日成为 Kubernetes 领域里的老司机,早日开启容器的自动驾驶模式,谢谢大家! 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 概述 2 | 3 | 随着容器及微服务概念的普及,各个公司都在都在探索如何打造生产环境可用的、高效的容器调度平台,而 Kubernetes 的出现使这种探索变得更简单。Kubernetes 是 Google 在 2014 年基于其 Borg 系统的实践经验开源的一套标准化的、可扩展的容器管理平台。 4 | 5 | 发展至今, Kubernetes 已经成为了容器编排领域事实上的标准,并且大量的公司都已在生产中使用,无论是国外的谷歌、 亚马逊、 GitHub,还是国内的阿里,腾讯,京东,滴滴及其他中小公司都在进行着大量的探索与实践。 6 | 7 | 在生产环境,为了能够快速进行产品迭代,不再受单体架构的拖累,微服务的概念也在实践中逐步推进,从原先的单体集中式的服务,拆分为多个松耦合的微服务。用容器部署微服务已是大势所趋,生产中大量使用容器,则容器编排变的愈发重要。Kubernetes 在容器编排领域目前已成为事实上的标准,大量公司均已在生产中推进,此时,无论是开发工程师还是运维工程师,需要了解并掌握 Kubernetes 的基础技能。 8 | 9 | 为了让大家能够更好的掌握 Kubernetes 及其相关生态,我打算做一系列的视频课程,本套视频是这个系列的第一部分--基础篇,接下来我还会做进阶篇。在基础篇中我将一步步引导你去实践如何部署一个测试目的的Kubernetes 集群;如何将微服务部署到 Kubernetes 集群上。在接下来的进阶篇中,我将带来你进入更高级的主题,包括如何搭建生产环境使用的高可用性 Kubernetes 集群;如何搭建企业级私有仓库;如何配置持续集成与部署(CI/CD)流水线;如何为 Kubernetes 配置持久化存储;如何配置 Kubernetes 网络;如何监控 Kubernetes 集群及其部署的微服务 等等。 10 | 11 | 如果你对视频中讲解的知识有什么疑问,欢迎扫描下面二维码加入 QQ 群(774607973)进行提问,如果你对我们有什么建议,也欢迎加如QQ群,谢谢! 12 | 13 | ![QQ群](https://github.com/findsec-cn/k101/raw/master/docs/qq.jpg) 14 | 15 | 也可以关注我们的微信公众号: 16 | 17 | ![微信公众号](https://github.com/findsec-cn/k101/raw/master/docs/wechat.jpg) 18 | 19 | ## 你会学到什么? 20 | 21 | - Docker 镜像打包并运行容器 22 | - Kubernetes 基本概念 23 | - Kubernetes 基础架构 24 | - 从零搭建 Kubernetes 测试集群 25 | - 部署微服务到 Kubernetes 集群 26 | 27 | ## 适宜人群 28 | 29 | - 对 Docker有一定了解,希望能进入 Kubernetes 的各领域工程师 30 | - 正在或即将在生产环境使用 Kubernetes 的开发工程师 31 | - 需要维护 Kubernetes 的运维工程师 32 | 33 | -------------------------------------------------------------------------------- /config/nginx/frontend.conf: -------------------------------------------------------------------------------- 1 | upstream hello { 2 | server hello.default.svc.cluster.local; 3 | } 4 | 5 | upstream auth { 6 | server auth.default.svc.cluster.local; 7 | } 8 | 9 | server { 10 | listen 443; 11 | ssl on; 12 | 13 | ssl_certificate /etc/tls/cert.pem; 14 | ssl_certificate_key /etc/tls/key.pem; 15 | 16 | location / { 17 | proxy_pass http://hello; 18 | } 19 | 20 | location /login { 21 | proxy_pass http://auth; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /config/nginx/hello-v2.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name hello.ku.app; 4 | location / { 5 | include uwsgi_params; 6 | uwsgi_pass 127.0.0.1:8000; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /config/nginx/hello.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name hello.ku.app; 4 | location / { 5 | include uwsgi_params; 6 | uwsgi_pass unix:///tmp/uwsgi.sock; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /config/tls/ca-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAwYxTGfCJQsegBeE8n4QV1aowpU6FcSYruK7iH8PVsNUWCg/z 3 | fOiG5YDU7IC9TwZHM2GnAVRHxTnOqyjUGig6sb9CLmDqS4AkZWaW+wmtul8ZyMiU 4 | 5jDDM/M1tTbojuquK8loTlmZ8eITFg4QDwmovZQyMHRfB3pS/FevnrIRGLnPbpaw 5 | H+XGw5oZkNLzj63/AElrIXrOIbHv+flAscFzLekwnCe623LYURmMslnNXkgTMpvx 6 | KpCGBRJ/R2vGsl/5uma4o+IhfppU/Hx16uBTLVxbFPL9BxQTjLCzcP+a37JTaCds 7 | Wo9SafhQOea0xkbWQJwyv7tEtk/l/A4n7MKDbwIDAQABAoIBAE2bHH8cKY1zScDR 8 | zWMQrUidEyBVWcBC0+kbhmPCPF7JMisatkDxY5WGkNm7zSxwkgASOcqYpqZ4RVvv 9 | 5QwP8WjwDXNXPNrFKNLXzdYezWAbXdVaSAn8p2ifLnvY5mrXwrqf6Yjw+H86bPi8 10 | 7sd40gYh8/Xl02zGKZww9KQnNh+5PgHRmJsqbdrg747cVneR8tMwHN4oeWeGe6/R 11 | h7Kn81DtncUlV/zvD07wtHgsz58jRHYqSjO0FoA0tHIucUPEkTmfbbrgK+4yaDuF 12 | LEHLrYxqVg1WFPUhNVlWb8FufGK054EKzSVWPcrcMPBK4rbTc2eymx1pMwZGtMwo 13 | w9mLj+ECgYEA9g0yBz/s+Cn77me8u7Sz3dfiTNjcSTe19jpeL2xgAotZ/sP9vBcn 14 | 1PnWlReSjX59UPRhEI6oo4TaqAFfCH3inHdqD9pXZFWyU5VYJdY3s70ahbg9n8Ef 15 | pl08vwr+CzSbA2OUeBoLfYZ7hNmNFP4SuyuOqK1AiSn7/JZOCFNS5OcCgYEAyV+u 16 | ttFoQ9KK1hNw7DMyTEjGqsyrJinVmY2ZFbYoRjW2d7TeIgyvbl3J4UlwkThlgSIW 17 | ekx3f8rKgox0yvcJ83Y5M81wkGbIusEz3Pq55Fo4zsyaiDRDAC/JSKr/G6YrJSxR 18 | gW570Au91Xvc+a8WSwVoOra57zSOGZKqUh5IlDkCgYBR7LDUox9GvcvpZFb99LvS 19 | yLfLuIUYR9lpQ6PqjF4nWri7UAyi3N7hVdJxz+h2/j/Bfaz381gJIgof2F0JGckj 20 | KcuBvcRNXw9CLz6rUnk3emZjUaYLFCVyoibAwWs21ewrI7PijWF4CRgFct47uCEK 21 | ewVD+nO7d+Q0BOO0d/HozwKBgHWRDTni7FKcez4cv5LHGRh8bLCPKWTwi6pIhxWr 22 | 8bt75Hni+MU8TrfKvfBvpe7C1FAeDK1+M05CoRSy2AUfUYn4fdEGoi9MMukFnzfm 23 | kd0F56Ckx5u5l1xmiceJPcNwskPTqgo87MA7+qrG0+5aEFPgZkfRIqDLOCMqA5JJ 24 | 5+nRAoGBAJlewHXeEAxrN9fLZEyxL1QF1/vy/E8BGIB6ZxkQwfjoGUTGxfi7isA9 25 | W1gHR0H39vjCfBse3gYVTvm7X4w4Rgksvzx9Cfnj2QiBIWRcMbcrWuQTaXSWll/O 26 | WG5V4LJTwEo/So/EpoKNjIeC7+dHLi75gZHIcG1t4vPAf5gwCO+5 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /config/tls/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC/TCCAeWgAwIBAgIJAOqHnLeBjLOhMA0GCSqGSIb3DQEBCwUAMBUxEzARBgNV 3 | BAoMCkt1YmVybmV0ZXMwHhcNMTcxMjI4MDA0NzEyWhcNMjcwOTI3MDA0NzEyWjAV 4 | MRMwEQYDVQQKDApLdWJlcm5ldGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 5 | CgKCAQEAwYxTGfCJQsegBeE8n4QV1aowpU6FcSYruK7iH8PVsNUWCg/zfOiG5YDU 6 | 7IC9TwZHM2GnAVRHxTnOqyjUGig6sb9CLmDqS4AkZWaW+wmtul8ZyMiU5jDDM/M1 7 | tTbojuquK8loTlmZ8eITFg4QDwmovZQyMHRfB3pS/FevnrIRGLnPbpawH+XGw5oZ 8 | kNLzj63/AElrIXrOIbHv+flAscFzLekwnCe623LYURmMslnNXkgTMpvxKpCGBRJ/ 9 | R2vGsl/5uma4o+IhfppU/Hx16uBTLVxbFPL9BxQTjLCzcP+a37JTaCdsWo9SafhQ 10 | Oea0xkbWQJwyv7tEtk/l/A4n7MKDbwIDAQABo1AwTjAdBgNVHQ4EFgQUEdeeHGX3 11 | JLMqY/3onHTddbH4CPIwHwYDVR0jBBgwFoAUEdeeHGX3JLMqY/3onHTddbH4CPIw 12 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAp2VEkGpdPc0G8CFJ4Wp3 13 | BvV0zQqKz/3YYkbF9ADXiOzW+brysBlNsZuhoWjUHh7y+bjRVaFZfEYugA9OXqID 14 | r0zdd7AoiA0lnfI1LPsM08lnGj68O1m5IuvupkpPEIQfLIJSnAQTyLY7VV1OvxS6 15 | xnHYuf6UTX2kRqFSJ/RcGZY/9OXoDTQ9m+dQXHgYXM4SvCk6ePNPT7mTpaDbrze9 16 | gAQsisj/pS5AWnADwAasDr5xcRJ63DACshXlMvZ+cs5rkhyJj64FjU40H+fm2kFW 17 | vs4pxkVq/w9QkzbwncfWOErOmtjZWrNWqmgBAwovFTgWCqz30ZY8iBNg66Ody3R7 18 | 8Q== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /config/tls/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDcTCCAlmgAwIBAgIJAPm3kEfjP8dHMA0GCSqGSIb3DQEBCwUAMBUxEzARBgNV 3 | BAoMCkt1YmVybmV0ZXMwHhcNMTcxMjI4MDA0NzEyWhcNMjcwOTI3MDA0NzEyWjAt 4 | MRMwEQYDVQQKDApLdWJlcm5ldGVzMRYwFAYDVQQDDA0qLmV4YW1wbGUuY29tMIIB 5 | IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlLQoKf5Hm8S2WVF7AGnBuxlj 6 | 4auuLcPJVh+zeQZO4Lf5IatJBBnmLzWzvxbpo582RIQVPXOVr2Ax8WMDnPfiR3Gr 7 | Ff8Qg/ShQcK0f/T3M2k1HWNKjrGf9NxyuEem17Ubss2F4i0hMosfKy2XsRQweorx 8 | wmfNac+n2wO84s4FSFD9rM2sTRP2RFLcuub6jedD+wGhmGGNYXc/jUGHMVBDfllJ 9 | dE/6GUWgdzWFdGZE6zxDgpnf2OGLUEJ5tsC8RtxiQiAAr83JGJuc/a8PEfVX+fdv 10 | C4vgXyvJhhwjgGUrRTOsJC2OmIrnxssZDLD56VDwUn23cI4i4ovUYn+YvzzxdwID 11 | AQABo4GrMIGoMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYI 12 | KwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUP4siUUai0/emdvgNo0Wt 13 | uvPPOgAwHwYDVR0jBBgwFoAUEdeeHGX3JLMqY/3onHTddbH4CPIwKQYDVR0RBCIw 14 | IIcEfwAAAYIJbG9jYWxob3N0gg0qLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUA 15 | A4IBAQB/Pj7c23hFaFeIvW3UNPs0zRQ1Zu0UD3Opb5mGl1Nc0WxQBgMM9CCbui+x 16 | CyMm1m+OeZUrhROYtkghHC/ghJs6mX9efAW9Puzz2whK7hDqLY/AJkTBCK6syOe1 17 | hs+skmt6V3jmg2lMCVkIQ526ubndYkJLRay0AdpeLeokMypPsjYRNiuw7mpFQimz 18 | VQgClOwfB82WMGkaitgU1wrEzBB5XTodrfv51eUZvj66ZKn7vo8ChGgHET+71Cm/ 19 | VxpR7/PlxmJ7IHhZl9TmVO8qjNqhlLRsmDGenR6TU7bI0pNa+6bx7phljIAh7+Hu 20 | Eq3O4m0QURgzP+V4lHgst75223rk 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /config/tls/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAlLQoKf5Hm8S2WVF7AGnBuxlj4auuLcPJVh+zeQZO4Lf5IatJ 3 | BBnmLzWzvxbpo582RIQVPXOVr2Ax8WMDnPfiR3GrFf8Qg/ShQcK0f/T3M2k1HWNK 4 | jrGf9NxyuEem17Ubss2F4i0hMosfKy2XsRQweorxwmfNac+n2wO84s4FSFD9rM2s 5 | TRP2RFLcuub6jedD+wGhmGGNYXc/jUGHMVBDfllJdE/6GUWgdzWFdGZE6zxDgpnf 6 | 2OGLUEJ5tsC8RtxiQiAAr83JGJuc/a8PEfVX+fdvC4vgXyvJhhwjgGUrRTOsJC2O 7 | mIrnxssZDLD56VDwUn23cI4i4ovUYn+YvzzxdwIDAQABAoIBAFqqyf5ouxKfyysE 8 | gkHLOcMxhPP48JeY066+X3iAPyHHKpC71iY5AF9yl+kAOG56SeVWv3ibe/3VYj4y 9 | x+YyQfabuNwNi+1Y/+WPqOyH2R2wnSERBEmixcvPiecQUQseswe/Rk2UhLRDnTp/ 10 | bwkaLUDabPPCxL0qTsc8LTQAt7nSMhaVh3JDBZpGvKR2CgFDVoTu4PBnRNlmfu8o 11 | dSCjfkmhW+UZgiuLs8QKTRdhUa9FSXvGVRilUrFuXLlC3yTDl+VDewsDjfS2AUAw 12 | 6FebQDJVeVlW+fvQl2d+iXonD5FmVVLulrMfhWeY9iptNW/Wo+A8JXqREDoyMmCx 13 | +Th0zNECgYEAxc6xb9SM+OKQW8vFRZb3mI9XdTarMGMuyIBtgRPlhvxF1BQ2xru1 14 | kSwujhvkDDuWDYDppNtAvMXeHLQTxIokGj7IqfZr0ASUh902CO19JM+YZK0xtJGw 15 | iR7HimyWiubocAHQYSfCZ+/tLXtGz8APM56DiK6MI7QfskDcyIK5nR8CgYEAwHNc 16 | MVmwgvg9z7U+dOJZhtZbblrOA8Ii0WKKBrXJaBtx8G4GE0fyorW3IHCC7qD8HJ3y 17 | HCf0IoT6Z3SgHRIR33cXtO+ao6UcbEy8FaL7jG5NXEPQa+OOBx85lOb7vKM3Y52/ 18 | pHNm7i3J8Ise/ax01NFyhN7O6YM+HHzm1R2MyKkCgYEAoir3W0h1nqIYWbmwbIH9 19 | USzLNcRxCoV12Fk57WXDeiwej2VXFwzTKUaAkG8bQlAjj8SNSGOcKmdJ1lxoDGx4 20 | dq/cUUM+Vlc68jwQTbduLpynQnqfUntSsMf0LW8i6JOwIgvKq6wt/Io991im0DGU 21 | BOzCx27aY3cLuVbl6tkJlV8CgYBO6P5MXfI6QX9Ww4Iwev8qgopK3YDLmbadFEJ0 22 | LeW/gkFdzD9BeKbMgKXt7zRAlFHLihfT463+2XezI+bjBJ2/ex2FWxmVMAZPgcc9 23 | N+7czf16b3PuSQfbc7owi+V8m5ACkJQb4hW6Y5wBvYmfii79dEP4p0NADEhTdgNQ 24 | LyWiwQKBgQC6E20iuF48cWJOTsvoY4qXMYJdzHf4nfUIigQhbWpqyZHowKsbrrZS 25 | rxaJKwWI0A/M5gwK056Wd3RZncEy9XgNKE/GBWnfYF7OaZ3PAH+MJX4oFUJZ+04r 26 | F2TarZ2yFjtLwm88dLup1yO2WCvpVTrHG/LdLrB/Hn9nAFZtkcTzwA== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /config/tls/ssl-extensions-x509.cnf: -------------------------------------------------------------------------------- 1 | [v3_ca] 2 | keyUsage = critical, digitalSignature, keyEncipherment 3 | extendedKeyUsage = serverAuth, clientAuth 4 | basicConstraints = critical, CA:FALSE 5 | subjectKeyIdentifier = hash 6 | authorityKeyIdentifier = keyid,issuer 7 | subjectAltName = IP:127.0.0.1, DNS: localhost, DNS: *.example.com 8 | -------------------------------------------------------------------------------- /config/tls/update-tls.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | openssl genrsa \ 5 | -out ca-key.pem 2048 6 | 7 | openssl req \ 8 | -x509 \ 9 | -new \ 10 | -nodes \ 11 | -key ca-key.pem \ 12 | -days 3560 \ 13 | -extensions v3_ca \ 14 | -out ca.pem \ 15 | -subj "/O=Kubernetes" 16 | 17 | openssl x509 -in ca.pem -text 18 | 19 | openssl genrsa \ 20 | -out key.pem 2048 21 | 22 | openssl req \ 23 | -new \ 24 | -key key.pem \ 25 | -out csr.pem \ 26 | -subj "/O=Kubernetes/CN=*.example.com" 27 | 28 | openssl x509 \ 29 | -req \ 30 | -in csr.pem \ 31 | -CA ca.pem \ 32 | -CAkey ca-key.pem \ 33 | -CAcreateserial \ 34 | -out cert.pem \ 35 | -extensions v3_ca \ 36 | -extfile ssl-extensions-x509.cnf \ 37 | -days 3560 38 | 39 | openssl x509 -in cert.pem -text 40 | 41 | rm ca.srl 42 | rm csr.pem -------------------------------------------------------------------------------- /docs/Kubernetes技术实践(基础篇).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/Kubernetes技术实践(基础篇).pdf -------------------------------------------------------------------------------- /docs/configmap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/configmap.jpg -------------------------------------------------------------------------------- /docs/deployment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/deployment.jpg -------------------------------------------------------------------------------- /docs/k8s-master.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/k8s-master.jpg -------------------------------------------------------------------------------- /docs/k8s-node.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/k8s-node.jpg -------------------------------------------------------------------------------- /docs/k8s.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/k8s.jpg -------------------------------------------------------------------------------- /docs/micoservice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/micoservice.jpg -------------------------------------------------------------------------------- /docs/pod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/pod.jpg -------------------------------------------------------------------------------- /docs/pods-to-pods.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/pods-to-pods.jpg -------------------------------------------------------------------------------- /docs/pods-to-service.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/pods-to-service.jpg -------------------------------------------------------------------------------- /docs/qq.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/qq.jpg -------------------------------------------------------------------------------- /docs/replicaset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/replicaset.jpg -------------------------------------------------------------------------------- /docs/rollout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/rollout.jpg -------------------------------------------------------------------------------- /docs/service-nodeport.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/service-nodeport.jpg -------------------------------------------------------------------------------- /docs/service.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/service.jpg -------------------------------------------------------------------------------- /docs/wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/findsec-cn/k101/40ddc06b57f18123bac0c1b0098c877aa434b0c3/docs/wechat.jpg --------------------------------------------------------------------------------