容器技术
容器借鉴了集装箱的概念,集装箱解决了什么问题呢?无论形状各异的货物,都可以装入集装箱,集装箱与集装箱之间不会互相影响。由于集装箱是标准化的,就可以把集装箱整齐摆放起来,装在一艘大船把他们都运走。有了集装箱,就再也不需要为各种货物单独准备专门运输的船了。如果把容器比作集装箱的话,应用就相当于集装箱里的货物。
容器(Container):一种轻量级的虚拟化技术,这种技术允许操作系统上的用户空间被分割成几个独立的单元在内核中运行,彼此互不干扰。这样一个独立的空间,就称之为一个“容器”。
容器为应用软件及其依赖组件提供了一个资源独立的运行环境。应用软件所依赖的组件会被打包成一个可重用的镜像,镜像运行环境并不会与主机操作系统共享内存、CPU和硬盘空间,由此也保证了容器内部的进程与容器外部进程的独立关系。
举个例子,一个操作系统,可以类比成一套公寓,那么容器就相当于公寓中的一个房间,大家共享同一个客厅,厨房和卫生间。但是房间和房间之间彼此隔离,一个房间里面的人的活动,不会影响到其他房间的住客。房间也有门,因此有一定的安全隔离保障。
容器的技术特点:
• 容器是自包含的。它打包了应用程序及其所有依赖,可以直接运行。
• 容器是可移植的。可以在几乎任何地方以相同的方式运行。这就可以确保应用在开发环境、测试环境、生产环境等都有完全一样的运行环境。
• 容器是轻量级的。占用资源很少,可以秒级启动。
• 容器是互相隔离的。同一主机上运行的多个容器,不会互相影响。
这两种架构,一个很直观的对比结果是,容器的运行不需要再额外安装虚拟机操作系统。可见,容器是一种比虚拟机更轻量级的虚拟化技术,支持秒级启动具备更好的快速扩展能力,具备更好的跨平台迁移能力。当然也由于这个原因,容器的隔离性上不如虚拟机。两者主要差异如下:
• 虚拟机OS占用了较多资源,一个虚拟机基本是GB 级的,一个容器可小至几MB。
• 虚拟机的启动时间一般是分钟级的,而容器的启动时长是毫秒级的。
• 由于容器的轻量级,它具备了更好的快速扩展能力。
容器比虚拟机具备更好的跨平台迁移能力,如虚拟机无法从Vmware迁移至KVM。
docker
Docker是一个开源的应用容器引擎,它实现了容器化技术的一种具体形式。
Docker核心概念
Docker 有三大核心概念,分别是容器(Container)、镜像(Image)和仓库(Repository)。
• 镜像:类似虚拟机的镜像,通俗的理解就是安装文件,相当于是容器的模板,可以根据不同的镜像来创建不同的容器。镜像和容器的关系可以理解为面向对象中类和实例对象的关系。
• 容器:类似一个轻量级的沙箱,容器是根据镜像创建的应用运行实例,具体运行应用程序的一个进程,可以将其启动、开始、停止、删除,而这些容器都是相互隔离、互不可见的。
• 仓库:类似代码仓库,是 Docker 集中存放镜像文件的场所。仓库有本地镜像仓库 Docker-Registry 和公共镜像仓库 Docker Hub,平时使用本地仓库的镜像,没有的话可以去公共镜像仓库下载。
可以用编程中面向对象的概念来做类比:镜像可以看成一个类,容器可以看做是类的实例化对象。一个类可以有多个对象。同理,一个镜像可以有多个容器。容器是由镜像实例化而来。简单来说,镜像是文件,容器是进程,仓库是保存镜像的地方。
通过Docker命令,运行一个容器一般情况下只需要三步:
- pull:从镜像仓库中将相应的镜像下载下来;
- list:当镜像下载完成之后就可以通过docker images 来查看本地镜像,会列出一个完整的镜像列表,可以在列表中选中想要的镜像;
- run:当选中镜像之后,就可以通过 docker run 来运行这个镜像,得到想要的容器。当然可以通过多次运行得到多个容器。
采用容器技术搭建并运行企业网站,需要经历三个主要过程:
• 构建(build):把应用代码和运行环境一起,制作成镜像文件
• 发布(release):将镜像文件发布到镜像仓库。
运行(run):从镜像仓库中获取镜像并运行。
docker和k8s的关系
Docker 和 Kubernetes(通常缩写为 k8s)是容器化技术领域中两个互补的工具,它们共同工作以提供强大的应用程序部署和管理解决方案。
Docker:
Docker 是一个开源的容器化平台,它允许开发者将应用及其依赖打包到一个轻量级、可移植的容器中。
容器与底层系统隔离,确保了应用程序在不同环境中的一致性。
Docker 提供了容器的创建、运行、分发和管理的工具,如 Docker Engine 和 Docker Hub。
Kubernetes:
Kubernetes 是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用程序。
它提供了高级的集群管理功能,包括服务发现、负载均衡、自我修复(自动替换失败的容器)、存储编排等。
Kubernetes 允许在集群中运行和管理成千上万的容器,支持服务的弹性伸缩和高可用性。
Docker 和 Kubernetes 的关系:
容器化:Docker 用于创建容器化的应用程序,而 Kubernetes 用于管理这些容器的生命周期和部署。
互补性:Docker 提供了容器的运行时环境,而 Kubernetes 则提供了容器的管理和编排。
生态系统:Kubernetes 支持多种容器运行时,包括 Docker,但也支持其他如 containerd、CRI-O 等。
部署和管理:Docker 可以独立使用来运行和管理单个容器,而 Kubernetes 提供了大规模容器部署和管理的能力。
服务网格:在 Kubernetes 上,Docker 容器可以作为 Pod 运行,Kubernetes 负责 Pod 的调度、网络、存储等。
社区和企业支持:两者都有庞大的社区和企业支持,Docker 由 Docker Inc. 维护,而 Kubernetes 由 Cloud Native Computing Foundation (CNCF) 维护。
总的来说,Docker 为应用程序提供了容器化的基础,而 Kubernetes 则为这些容器化的应用提供了一个强大的运行平台,两者结合使用可以实现高效的持续集成和持续部署(CI/CD)流程,以及在云环境中的弹性伸缩和高可用性部署。
K8s
容器编排是指自动化容器的部署、管理、扩展和联网。通过容器编排,可以构建跨多个容器的应用服务、跨集群调度容器、扩展这些容器,并持续管理它们的健康状况。容器编排给容器技术带来了巨大的价值,包括:
• 自动化部署:支持根据副本数量,回滚,重启等策略自动部署容器。
• 服务发现与负载均衡:自动发现增加的容器,并进行流量的负载均衡。
• 自动化容器恢复:自动对容器进行健康检查,并根据策略进行重启。
• 弹性伸缩:支持工作节点、容器的自动扩缩容。
一个容器编排平台的核心功能:首先可以自动生成容器实例,并且生成的容器可以跨服务器的,帮助提高可用性和性能,同时还有健康检查、容错、可扩展、网络、服务发现、滚动升级等功能,可以很好地解决需求与资源的匹配编排问题。
容器编排平台的市场竞争曾经非常激烈,主流的有三个:Docker Swarm、Mesos Marathon和Kubernetes。它们各有特点,但同时满足上面上述能力的,只有Kubernetes。
Kubernetes 设计思想
Kubernetes 基于API管理一切的思想,采用声明式即“面向结果”的API,围绕 etcd(分布式存储与协调数据库) 构建出来的一套 “面向终态” 的编排体系。
当用户向 Kubernetes 提交了一个 API 对象(Kubernetes Object)的期望状态(Spec)之后,Kubernetes 会负责保证整个集群里各项资源的当前状态(Status),都与 API 对象描述的需求相一致。更重要的是,这个保证是一项 “无条件的”、“没有期限” 的承诺:对于每个保存在 etcd 里的 API 对象,Kubernetes 都通过启动一种叫做 “控制器模式”(Controller Pattern)的无限循环,不断对 etcd 里的 API 对象的变化进行监视(Watch),然后执行控制器(Controller)里定义的编排动作的响应逻辑,进行调谐,最后确保整个集群的状态与 API 对象的描述一致。
为了实现“面向终态”的管理,支持自动化部署、扩缩和管理容器应用,Kubernetes采用了控制平面和计算平面分离的架构。控制平面是整个集群的大脑,负责控制、调度集群资源;计算平面负责运行容器化应用,是控制平面调度的对象,通过增加或减少工作节点实现容器集群处理能力的扩缩。控制平面由至少一个管理节点(Master节点)组成,通常会采用三个管理节点组成高可用集群(一个管理节点提供服务,剩下两个管理节点为备用节点,当管理节点不可用时,从备用节点中自动选举一个出来成为管理节点)。计算平面则由多个工作节点(Node节点)组成。
K8S集群分为Master节点和Node节点,Master节点负责调度分配任务,Node节点接受Master调度进行工作。
1.1 Master节点组件
/1. API Server
集群的统一入口,各组件协调者,以RESTful API方式提供接口服务,所有对象资源的增删查改和监听操作都交给API Server处理后再提交给Etcd存储。
2. Controller Manager
负责维护集群的状态,比如故障检测、自动扩展、滚动更新等。一个资源对应一个控制器,而Controller Manager就是负责管理这些控制器的。
工作负载是一种Controller,在Kubernetes中还有Node Controller等其他多种控制器。每种控制器都是一个智能系统,通过API Server提供的(List-Watch)接口实时监控集群中资源对象的变化,当资源对象因某些原因发生状态变化时,Controller会执行相应逻辑使其最终状态调整到期望状态。比如:某个Node意外宕机时,Node Controller会及时发现此故障并执行自动化修复流程,确保集群始终处于预期的工作状态。
每种Controller都负责一种特定的资源控制器,Controller Manager是Kubernetes中各种Controller的管理者,是集群内部的管理控制中心,也是Kubernetes自动化功能核心。
3. Scheduler
负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上。
4.etcd
分布式键值存储系统,用于保存群集状态数据,比如Pod、Service等对象信息。
1.2 Node组件
Node节点(工作节点)是Kubernetes集群中的工作节点,Node节点上的工作由Master节点进行分配,比如当某个Node节点宕机时,Master节点会将其上面的工作转移到其他Node节点上。Node节点在集群中主要负责如下任务:
• 负责管理所有容器(Container)。
• 负责监控/上报所有Pod的运行状态。
一个Node节点主要包含三个组件:kubelet、kube-proxy、Container Runtime。
- kubelet
kubelet是Master在Node节点上的Agent,管理本机运行容器的生命周期,比如创建容器、Pod挂载数据卷、下载secret、获取容器和节点状态等工作。kubelet将每个Pod转换成一组容器。 - kube-proxy
为Service提供cluster内部的服务发现和负载均衡。Service是通过Selector选择的一组Pods的服务抽象,提供了服务的负载均衡和反向代理的能力。实现 Service 负载均衡和反向代理功能,是通过kube-proxy实现的。kube-proxy 运行在每个节点上,监听 API Server 中服务对象的变化,通过管理 iptables 来实现网络的转发。
Service的负载均衡实现的过程共分为五步,如下: - 运行在每个Node节点的kube-proxy会实时的watch Service和Endpoints(IP+端口)对象, 当用户在Kubernetes集群中创建了含有Label的Service之后,同时会在集群中创建出一个同名的Endpoints对象,用于存储Service下的Pod IP。
- 当每个Node节点的kube-proxy感知到Service和Endpoints的变化之后,会在各自的Node节点上打开代理端口,并设置相关的iptables或IPVS转发规则。
- 客户端访问Service的ClusterIP。
- 客户端请求会经过iptables/IPVS,会被重定向到kube-proxy的代理端口。IPVS模式的调度由IPVS完成,其他功能仍是iptables实现。
- kube-proxy将请求发送到真实的后端Pod。
Kubernetes中如何实现多个环境的隔离?
在Kubernetes容器集群中,同一类型的资源名称是唯一的。在实际中,我们往往需要将不同业务、不同的项目、不同的环境进行隔离管理,这就需要通过命名空间Namespace进行分区管理。
Namespace 是用来做集群内部的逻辑隔离的,它包括鉴权、资源管理等。Kubernetes 的每个资源,比如 Pod、Deployment、Service,都属于一个 Namespace,同一个 Namespace 中的资源命名唯一,不同的 Namespace 中的资源可以重名。在一个Kubernetes集群中可以拥有多个命名空间,它们在逻辑上彼此隔离。
不过,Kubernetes也有一些资源隶属于集群级别的,如Node、Namespace和Persistent Volume等,不属于任何名称空间,所以这些资源对象的名称必须全局唯一。
在K8s 中部署一个前后端应用
编写Dockerfile
拷贝前端工程dist目录至/frontend,并进行目录授权
from nginx
copy ./dist /frontend
run chown nginx.nginx /frontend -R
copy nginx.conf /etc/nginx/conf.d/default.conf
编写nginx.conf文件
server{
listen 80;
server_name localhost;
root /frontend;
index index.html index.htm;
location /login {try_files $uri $uri/ /login.html;}
}
backend-dp.yaml
由于我们服务是无状态服务,使用Deployment进行部署,Deployment拥有更加灵活强大的升级、回滚功能,并且支持滚动更新
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
selector:
matchLabels:
app: backend
replicas: 1
template:
metadata:
labels:
# service 会根据此标签来查找此pod
app: backend
version: latest
spec:
containers:
- name: backend
image: “dweizhao/backend:latest”
imagePullPolicy: Always
backend-svc.yaml
Service相当于Spring cloud中Ribbon的作用,提供了服务发现和负载均衡的功能,而不用关心具体服务实例有多少个,在 k8s的服务实例就是Pod,这里我们使用ClusterIP类型,因为是通过Ingress在集群内访问,通过 app:backend标签,来查找对应pod,所以 pod 的label必须包含app:backend
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: ClusterIP
ports:
- name: backend-http
port: 8080
targetPort: 8080
protocol: TCP
selector:
# 根据标签查找 pod
app: backend
之后在服务器上创建命名空间:
kubectl create namespace k8sdemo
部署:
kubectl create namespace k8sdemo && kubectl apply -f backend-dp.yaml -f backend-svc.yaml -f frontend-dp.yaml -f frontend-svc.yaml -f ingress.yaml -n k8sdemo
k8s常用命令
#查看pods列表,这里主要是看pod状态
kubectl get pods -n tbds(n后面是namespace)
#查看某个pod的日志
kubectl logs tm-platform-96c9cd9d-w6zr8 -n tbds
#查看pod的详细信息,这些信息包括了 Pod 的配置、状态、事件等
kubectl describe pod kubectl logs tm-platform-96c9cd9d-w6zr8 -n tbds
#在pod中启动一个交互式shell,可以在这个shell中执行命令
kubectl exec -it tsf-data-gateway-86f59d85-vlvgq(pod名称) -n tbds -- bash
#获取应用列表
kubectl get app -n tbds
#删除某个应用
kubectl delete app product-kylin-sp2-es-x86(应用名称) -n tbds
#获取容器的configmap
kubectl get -o yaml configmap te-elasticsearch-config(config名称) -n tbds
#或者这样写:
kubectl get cm my-configmap -o yaml
#查看某个secret的值(渲染后的)
kubectl get secret secret-tbdsnew -o yaml -n default
#查看pod的资源使用情况
kubectl top pod <pod-name> -n <namespace>
#查看所有命名空间
kubectl get namespaces
#创建命名空间
kubectl create namespace tbds
#将base64编码的字符串进行解码
echo "dGJkcy1pbWFnZXM=" |base64 --decode