docker和k8s基础知识分享
本文最后更新于:2023年8月15日 晚上
Docker
什么是docker
- docker是一个开源的软件部署解决方案;
- docker也是轻量级的应用容器框架;
- docker可以打包、发布、运行任何的应用(Build,Ship,Run anywhere)。
- Docker 的基础是 Linux 容器(LXC)等技术。在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。
Docker vs 传统虚拟化
容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。相比传统虚拟化技术,Docker省去了操作系统的资源占用,达到了更高的资源利用率.
为什么用Docker
- 高效、轻量
对比虚拟机,Docker提供了一个经济、高效、可行的方案,可以节约出更多的资源投入到业务中去,让应用程序产生更高的效益。
- 快速、一致交付
在本地容器中得到一套标准的应用或服务的运行环境,简化开发的生命周期。对于整个应用迭代来说,更加适合持续集成( Continuous Integration )和持续交付( Continuous Delivery )。
- 跨平台部署和动态伸缩
很轻松的运行在开发者本地的电脑,云服务器,甚至是混合环境中;同时,轻量性和高可移植性能够很好的帮助我们完成应用的动态伸缩,大幅提高应用的健壮性。
- 完美契合微服务
微服务架构本身就意味着需要对若干个容器服务进行治理,每个微服务都应可以独立部署、扩容、监控,而Docker正是为此而生。
QuickStart
- 上手
假设我们需要在本地安装一个mysql数据库,如果是以前,我们需要下载、安装、配置等,但是有了docker,简单执行一条命令即可:
1 | |
docker run命令会为我们启动一个容器,其中--name参数指定了容器的名字,-e参数指定容器了的环境变量,Docker会将环境变量设置到启动容器的环境变>量中.-p指定了容器的端口映射,Docker容器运行在一个独立的网络环境中,需要通过端口映射来暴露服务.
可以看到输出结果如下:
1 | |
在执行docker run时,Docker首先会去Docker Server上查找对应的镜像,如果找不到,再去配置的镜像仓库服务器(Registry)查找,找了之后,再去对应的镜像仓库(Repository)下载镜像。可以看到镜像的下载是分了很多层的,这是因为Docker镜像都是由一层一层的只读层(Layer)堆叠而成的,而容器则是由多个只读层加上一层读写层。
启动成功后,我们尝试连接数据库:
1 | |
可以看到连接成功,mysql版本号为最新8.0.16,如果我们想切换到5.6版本呢?
1 | |
mysql:5.6中的5.6即是版本号,这里对应的其实是Docker镜像的标签(TAG),Docker通过标签来对镜像的版本进行定义,如果不指定标签,则默认使用
latest。
通过更换镜像的标签,我们可以运行不同版本的镜像而无需重复下载->配置->启动这一步骤,这便是Docker优于传统部署的地方。
- 构建自己的镜像
接下来我们来写一个简单的计数器应用k8s-demo并将其构建为Docker镜像,应用使用Go语言开发,使用go module 作为依赖管理工具,redis作为存储,通过REST API对外暴露接口.
接口列表:
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /score | 获取当前分数 |
| PUT | /score | 增加分数 |
| DELETE | /score | 减少分数 |
连接Redis的代码:
1 | |
其中连接redis的参数信息全部来自于系统的环境变量,这些都需要我们在启动的时候指定。
因为镜像中无法翻墙,所以我预先使用go mod vendor将依赖包下载到项目目录,在构建过程中直接使用项目目录的依赖。
Dockerfile:
1 | |
一个标准的Dockerfile一般包含两部分
FROM <IMAGE-NAME>表示镜像的基础镜像,我们已经知道一个Docker镜像是由多个只读层组成的,而构建一个新的镜像就相当于在原有的只读层基础上增加了若干层,其中,Dockerfile中的每一行命令都对应一层.ENTRYPOINT ["COMMAND"]或CMD ["COMMAND"]是容器启动时运行的命令,每一个Docker容器都会有一个前台程序(即ENTRYPOINT或CMD指定的命令)在运行,可以认为这个前台程序的生命周期=容器的生命周期,程序停止,容器也就停止了。
使用docker build命令来构建镜像
1 | |
可以看到
FROM scratch这里并没有生成layer,这是因为scratch这个基础镜像比较特殊,它相当于什么都不做。
推送镜像到Docker Hub(需要先注册Docker Hub账号)(可选)
1 | |
启动容器
因为应用依赖redis,所以我们使用docker-compose来启动两个关联的容器(应用和redis)。
docker-compose.yml
1 | |
启动应用:
1 | |
可以使用docker-compose logs -f来查看启动过程.
1 | |
Docker架构
Docker使用c/s架构,client 实现容器和镜像的管理,为用户提供统一的操作界面.client通过REST API与server进行通信,在构建容器时,server首先从本地查找镜像,如果找不到,再从可用的Docker regisry上下载.client和server可以运行在同一个机器,也可以跨主机远程通信.
Docker核心概念
- 镜像(image)
Docker镜像就是一个只读的模板。例如:一个镜像可以包含一个完整的操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。Docker提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。Docker使用UFS(Union File System)来将多个只读文件(Read only layer)堆叠到一起。
- 仓库(repository)
仓库是集中存放镜像文件的场所。仓库分为公开仓库(Public)和私有仓库(Private)两种形式。当用户创建了自己的镜像之后,可以使用push命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull下来就可以了。
- 容器(container)
Docker 利用容器(Container)来运行应用。容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。因为一个容器就是一个完整的操作系统,所以可以实现Run anywhere的效果。容器实际上就是在镜像的最上层加上一层可读写层。
- 网络(network)
在 Docker 中,实现了强大的网络功能,我们不但能够十分轻松的对每个容器的网络进行配置,还能在容器间建立虚拟网络,将数个容器包裹其中,同时与其他网络环境隔离。
- 数据卷(volume)
基于Docker 底层的 Union File System 技术。在 UnionFS 的加持下,除了能够从宿主操作系统中挂载目录外,还能够建立独立的目录持久存放数据,或者在容器间共享。
Docker安装部署
Docker安装非常简单,windows系统可以直接从官网下载exe安装包,linux系统也可以通过添加repo然后使用apt/yum直接安装,具体步骤可以百度。
ps:对于windows系统,新版的Docker for windows需要启用Hyper-v,而旧版的Docker ToolBox依赖VM VitualBox,如果使用旧版的安装,系统又启用了hyper-v,则需要手动在创建Docker machine时指定使用hyper-v还是VM VitualBox。
Docker常用命令
获取镜像
1 | |
从仓库获取所需要的镜像。
使用示例:
1 | |
拉取镜像时,如果没有指明registry,则默认从Docker Hub拉取;如果没有指定所有者,默认使用official;如果没有指定tag,默认使用latest。
因为Docker Hub镜像仓库在国外的原因,拉取镜像会很慢,推荐使用阿里云镜像加速,具体使用参照阿里云文档: 容器镜像服务-镜像加速器 .
查看镜像列表
1 | |
列出所有已经下载到server的镜像
使用示例:
1 | |
在列出信息中,可以看到几个字段信息
- 来自于哪个仓库,比如 ubuntu
- 镜像的标记,比如 14.04
- 它的 ID 号(唯一)
- 创建时间
- 镜像大小
构建镜像
1 | |
使用Dockerfile来构建一个镜像,Dockerfile相当于一个说明文档,告诉Docker应该如何构建镜像.
Dockerfile示例
1 | |
更详细的语法说明请参考 Dockerfile
编写完Dockerfile后可以使用docker build来构建镜像
1 | |
运行容器
1 | |
从指定镜像创建容器
部署docker后,可以使用以下命令来判断是否部署成功
1 | |
正常情况应该输出
1 | |
上传镜像
1 | |
用户可以通过 docker push 命令,把自己创建的镜像上传到仓库中来共享。例如,用户在 Docker Hub 上完成注册后,可以推送自己的镜像到仓库中。
运行实例:
1 | |
查看运行中的容器
1 | |
类似镜像,每一个容器都有一个唯一的container id标识.
其他
所有docker命令可以使用docker help查看,也可以在Docker官方文档上查看。
Docker Compose
当需要启动多个容器,且多个容器之间需要通信时,可以在docker run参数中指定一个共同的network来实现,但这样比较不方便,这时候,可以使用docker compose来同时启动多个容器.
Docker Compose是一个简单的Docker容器的编排工具,通过YAML文件配置需要运行的应用,然后通过compose up命令启动多个服务对应的容器实例。现版本的Docker中默认集成了Compose,不需要另外安装。
docker-compose.yaml示例:
1 | |
上图中指定了两个镜像k8s-dmeo和redis,使用同一个network:k8s-demo。
启动:
1 | |
其中-d 用来使其在后台启动
停止:
1 | |
Docker compose配置文件具体编写规则可以参考官网.
Kubernetes
Kubernetes是Google开源的容器集群管理系统,使用Go语言实现,其提供应用部署、维护、 扩展机制等功能。目前可以在GCE、vShpere、CoreOS、OpenShift、Azure等平台使用k8s。
国内目前Aliyun也提供了基于k8s的服务治理平台。如果是基于物理机、虚拟机搭建的Docker集群的话,也可以直接部署、运行k8s。在微服务的集群环境下,Kubernetes可以很方便管理跨机器的微服务容器实例。
为什么需要Kubernetes
真实的生产环境应用会包含多个容器,而这些容器还很可能会跨越多个服务器主机部署。使用 Kubernetes,可以快速精准地部署应用程序,进行即时伸缩、灰度发布。
Kubernetes能做什么
目前k8s基本是公认的最强大开源服务治理技术之一。其主要提供以下功能:
- 自动化地基于Docker或其他容器服务(runc/Containerd等)对服务实例进行部署和复制
- 以集群的方式运行,可以管理跨机器的容器,以及滚动升级、存储编排。
- 内置了基于Docker的服务发现和负载均衡模块
- K8s提供了强大的自我修复机制,会对崩溃的容器进行替换(对用户,甚至开发团队都无感知),并可随时扩容、缩容。让容器管理更加弹性化。
Kubernetes架构
Kubernetes整体上遵循C/S架构,CLI即kubectl命令行工具,CLI通过REST API与Server进行通信。
1 | |
其中server架构如下
- Master
- ETCD: 存储集群所有需持久化的状态,并且提供 watch 的功能支持,可以快速的通知各组件的变更等操作
- API Server: 接收外部的信号和请求,并将一些信息写入到 etcd 中。
- Controller Manager: 在后台运行着许多不同的控制器进程,用来调节集群的状态。
- Scheduler: Scheduler 是集群的调度器,它会持续的关注集群中未被调度的 Pod ,并根据各种条件,比如资源的可用性,节点的亲和性或者其他的一些限制条件,通过绑定的 API 将 Pod 调度/绑定到 Node 上。
- Node
Node是Kubernetes集群架构中运行Pod的服务节点,用来承载被分配Pod的运行,是Pod运行的宿主机
- Kubelet: 负责管控容器,Kubelet会从Kubernetes API Server接收Pod的创建请求,启动和停止容器,监控容器运行状态并汇报给Kubernetes API Server。
- Container Runtime: 容器运行时最主要的功能是下载镜像和运行容器,我们最常见的实现可能是 Docker , 目前还有其他的一些实现,比如 runc, Containered。
K8S 提供了一套通用的容器运行时接口 CRI (Container Runtime Interface), 凡是符合这套标准的容器运行时实现,均可在 K8S 上使用。 - Kube Proxy
负责为Pod创建代理服务,KubeProxy会从API Server获取所有的Service信息,并根据Service的信息创建代理服务,实现Service到Pod的请求路由和转发。
Kubernetes核心概念
- Namespace
Namespace是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或用户组。常见的pods, services, replication controllers和deployments等都是属于某一个namespace的(默认是default),而node, persistentVolumes等则不属于任何namespace。
Namespace常用来隔离不同的用户,比如Kubernetes自带的服务一般运行在kube-system namespace中。
Namespace定义实例:
1 | |
kubectl可以通过–namespace或者-n选项指定namespace。如果不指定,默认为default。查看操作下,也可以通过设置–all-namespace=true来查看所有namespace下的资源。
- Pod
在Kubernetes中,最小的管理元素不是一个个独立的容器,而是Pod,Pod是最小的,管理,创建,计划的最小单元。一个Pod是一个容器环境下的“逻辑主机”,它可能包含一个或者多个紧密相连并且共享磁盘的容器。
Pod定义文件示例:
1 | |
- Label
标签其实就一对 key/value ,被关联到资源上,比如Pod,标签可以用来划分特定组的对象(比如,所有女的),标签可以在创建一个对象的时候直接给与,也可以在后期随时修改,每一个对象可以拥有多个标签,但是,key值必须是唯一的。
- Label Selector
通过Label Selector,客户端/用户能方便辨识出一组对象。Label Selector是kubernetes中核心的组织原语。
API目前支持两种选择器:基于相等的和基于集合的。一个Label Selector一可以由多个必须条件组成,由逗号分隔。在多个必须条件指定的情况下,所有的条件都必须满足,因而逗号起着AND逻辑运算符的作用。
- Replication Controller
Replication Controller( 简称RC )是Kubernetes系统中的核心概念之一,简单来说,它其实是定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所以RC的定义包括如下几个部分:
- Pod期待的副本数(replicas).
- 用于筛选目标Pod的Label Selector.
- 当Pod的副本数量小于预期数量时,用于创建新Pod的Pod模板(template).
ReplicaSet是下一个版本的RC,它和RC的唯一区别是: ReplicaSet支持基于集合的Label Selector,当前我们很少单独使用ReplicaSet,它主要被Deployment这个更高层的资源对象所使用.
RC定义文件示例:
1 | |
- Deployment
Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用。典型的应用场景包括:
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续Deployment
Deployment定义文件示例:
1 | |
- Horizontal Pod Autoscaling
Horizontal Pod Autoscaling可以根据CPU使用率或应用自定义metrics自动扩展Pod数量(支持replication controller、deployment和replica set)。
- 控制管理器每隔30s(可以通过–horizontal-pod-autoscaler-sync-period修改)查询metrics的资源使用情况
- 支持三种metrics类型
- 预定义metrics(比如Pod的CPU)以利用率的方式计算
- 自定义的Pod metrics,以原始值(raw value)的方式计算
- 自定义的object metrics
- 支持两种metrics查询方式:Heapster和自定义的REST API
- 支持多metrics
HPA定义文件示例:
1 | |
- Service
Kubernete Service 是一个定义了一组Pod的策略的抽象,Service 通过 Label Selector来关联到一组Pod,并将这些Pod的特定端口暴露出去,这种暴露可以是ClusterIP或NodePort。
- NodePort: 使用这种方式暴露的Service,可以直接使用NodeIP:NodePort来访问。
- ClusterIP: ClusterIP是一个虚拟的ip地址,只在集群内可以访问,这种一般是用负载均衡服务来作转发。
Service定义文件示例:
1 | |
- Secret
Secret解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。Secret可以以Volume或者环境变量的方式使用。
Secret有三种类型:
- Service Account:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中;
- Opaque:base64编码格式的Secret,用来存储密码、密钥等;
- kubernetes.io/dockerconfigjson: 用来存储私有docker registry的认证信息。
- Ingress
Ingress 是一组允许外部请求进入集群的路由规则的集合。它可以给 Service 提供集群外部访问的 URL,负载均衡,SSL 终止等。
直白点说,Ingress 就类似起到了智能路由的角色,外部流量到达 Ingress ,再由它按已经制定好的规则分发到不同的后端服务中去。
Ingress 可以有多种控制器(实现),目前由官方维护的有两个: 适用于 Google Cloud 的 GLBC,当你使用 GKE 的时候,便会看到它;和 NGINX Ingress Controller,它是使用 ConfigMap 存储 Nginx 配置实现的。
Ingress并不是Kubernetes自带的,需要自己手动安装。以下说明一下NGINX Ingress Controller的安装步骤:
所有步骤皆为按配置文件创建资源,所以我只列了配置文件,安装时依次使用
kubectl apply -f filename安装即可。
以下配置文件全部来自官方文档,但是现在官方文档上改了,没有这个配置文件了,所以我把我保存的发出来.
- 创建Namespace
1
2
3
4
5
6
7apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx - 创建configMap(nginx配置文件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx - 创建帐号、角色及角色绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# Defaults to "<election-id>-<ingress-class>"
# Here: "<ingress-controller-leader>-<nginx>"
# This has to be adapted if you change either parameter
# when launching the nginx-ingress-controller.
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx - 创建nginx-ingress-controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
serviceAccountName: nginx-ingress-serviceaccount
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.24.1
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
# www-data -> 33
runAsUser: 33
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10 - 暴露Ingress Controller服务: Ingress 的作用在于将集群外的请求流量转向集群内的服务,而默认情况下,集群外和集群内是不互通的,所以必须将 NGINX Ingress Controller 暴露至集群外,以便让其能接受来自集群外的请求,这里使用NodePort的方式暴露。
1 | |
创建service之后,即可使用NodeIp:NodePort,根据定义的路由规则访问其他服务。
Ingress定义文件示例:
1 | |
Kubernetes安装部署
- 本地环境搭建
本地环境搭建简易可行的可选方式有两种:Kind和Minikube,这里推荐使用Kind.
Kind 是 Kubernetes In Docker 的缩写,顾名思义是使用 Docker 容器作为 Node 并将 Kubernetes 部署至其中的一个工具。官方文档中也把 Kind 作为一种本地集群搭建的工具进行推荐。
Kind安装
Kind 使用 Golang 进行开发,在仓库的 Release 页面,已经上传了构建好的二进制,支持多种操作系统,可直接按需下载进行使用。
示例:
1 | |
依赖
- Kind 的主要功能目前需要有 Docker 环境的支持。
- 如果需要操作集群,则需要安装 kubectl 命令行。安装方法可参考官方文档.
使用
1 | |
命令中的输出让我们使用export KUBECONFIG="$(kind get kubeconfig-path --name="sivdead")"来配置kubectl环境变量,但这种方式只在当前窗口有效,实际可以修改/etc/profile来使配置永久生效.
1 | |
修改完成后source一下即可使用kubectl获取集群信息
1 | |
可以看到单节点的Kubernetes已经搭建成功.
这时候使用docker ps,也可以看到对应的Node容器正在运行.
1 | |
在kind拉取Kubernetes相关镜像时,可能会因为镜像源被墙导致拉取不到镜像报错.这时我们可以使用配置文件的方式来指定使用国内镜像.
首先删除刚才报错的镜像
1 | |
然后创建kind-config.yaml
1 | |
使用该配置文件搭建集群:
1 | |
- 高可用集群搭建
高可用集群可以使用Kind或者Kubeadm来搭建,具体可以参考:
kubectl常用命令
kubectl命令行的语法如下:
1 | |
command: 子命令,用于操作集群资源对象的命令,常用命令:
- create: 创建资源对象
- apply: 从配置文件或stdin中对资源对象进行配置更新,也可以用于创建资源对象
- scale: 扩容/缩容一个Deployment、ReplicaSet、RC或Job中Pod的数量,可以将Pod数量设置为0来达到暂时停止应用的目的.
- delete: 删除资源对象,可通过-f=filename以配置文件格式指定删除的内容
- describe: 描述资源对象,describe在排查错误时非常有用
- get: 查看资源对象,可以使用
--watch来动态查看资源对象列表 - exec: 执行容器的命令,通常可以使用下列命令来进入到某个pod容器的bash命令行.
1
2# -c 指定容器名称,如果不指定,则默认使用pod中的第一个容器
kubectl exec -it podName -c containerName /bin/bash - logs: 查看容器的日志,参数
-f可以达到类似tailf的效果 - cp: 从容器中复制文件,要求容器中可以使用
tar命令,用法:1
kubectl cp <namespace>/<pod>:<src-filepath> <namespace>/<pod>:<dest-filepath> [options]
TYPE: 资源对象的类型,区分大小写,能以单数形式、复数形式、简写形式表示.例如下列3种TYPE是等价的.
1
2
3$ kubectl get pod
$ kubectl get pods
$ kubectl get po常用资源对象及其简写如下:
| 资源对象名称 | 简写 |
|---|---|
| configmap | cm |
| deployment | deploy |
| ingress | ing |
| node | no |
| namespace | ns |
| pod | po |
| replicationcontroller | rc |
| replicaset | rs |
| service | svc |
- NAME: 资源对象的名称,区分大小写.如果不指定名称,则系统将返回属于TYPE的全部对象的列表,例如
kubectl get pod将返回所有pod的列表 - flags: kubectl子命令的可选参数,例如使用
-n指定Namespace.常用参数:-n: 指定Namespace,如果不指定则使用default-o: 指定输出格式,可以将输出格式修改为yaml或者json等格式,也可以指定返回的字段。
Quick Start: 使用Kubernetes发布应用
我们使用之前编写的简单计数应用镜像。
首先,编写配置文件:
Namespace:
1
2
3
4apiVersion: v1
kind: Namespace
metadata:
name: demoDeployment:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: k8s-demo
name: k8s-demo-app
namespace: demo
spec:
selector:
matchLabels:
app: k8s-demo
template:
metadata:
labels:
app: k8s-demo
spec:
containers:
- image: sivdead/k8s-demo:0.0.1
imagePullPolicy: Always
name: k8s-demo
ports:
- containerPort: 8081
env:
- name: REDIS_HOST
value: "k8s-demo-redis"
- name: REDIS_PORT
value: "6379"
- name: REDIS_PASSWORD
value: "123456"Service:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15apiVersion: v1
kind: Service
metadata:
labels:
app: k8s-demo
name: k8s-demo-app
namespace: demo
spec:
selector:
app: k8s-demo
ports:
- port: 8081
protocol: TCP
targetPort: 8081
type: ClusterIPIngress
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: k8s-demo-ingress
namespace: demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /k8s-demo/(.*)
backend:
serviceName: "k8s-demo-app"
servicePort: 8081
host: sivdead.comRedis Deployment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: redis
name: k8s-demo-redis
namespace: demo
spec:
selector:
matchLabels:
app: redis
replicas: 1
template:
metadata:
labels:
app: redis
spec:
containers:
- image: redis:4.0
name: redis
ports:
- containerPort: 6379
args:
- '--requirepass 123456'Redis Service
因为redis不需要被集群外部使用,所以使用ClusterIP即可
1 | |
使用kubectl apply -f轮流创建资源后,修改/etc/hosts文件,增加sivdead.com 对应NGINX Ingress Controller的NodeIP:NodePort
1 | |
查看demo Namespace各资源的状态
1 | |
如果所有资源都在正常运行,使用curl测试接口:
1 | |
说明应用已经部署成功。
引用
- 掘金小册《Kubernetes从上手到实践-张晋涛》
- 电子工业出版社《Kubernetes权威指南》