k8s 查看ip地址属于哪个pod_认识k8s中的pod
序言在大部分的k8s教程中,都是先讲k8s的基本理论,对于刚刚接触k8s的同学来说,可能一脸懵逼,望而生畏,所以我带领大家一步步动手部署,在部署的过程中一步步教大家理解其中的概念,让更多的技术人员迈入k8s的大门。还没有安装k8s环境的可以参考我之前发布的文章:《从零开始,带你一步步如何用kubeadm安装k8s》工作目录:/data:工作的主目录/data/yaml:放置yaml文件使...
序言
在大部分的k8s教程中,都是先讲k8s的基本理论,对于刚刚接触k8s的同学来说,可能一脸懵逼,望而生畏,所以我带领大家一步步动手部署,在部署的过程中一步步教大家理解其中的概念,让更多的技术人员迈入k8s的大门。
还没有安装k8s环境的可以参考我之前发布的文章:
《从零开始,带你一步步如何用kubeadm安装k8s》
工作目录:
/data:工作的主目录
/data/yaml:放置yaml文件
使用到的镜像:
nginx:1.15.11
php:7.2-fpm
一、让我们认识k8s的Pod
1.1 部署第一个pod
在大部分web应用中都离不开nginx,所以我们先从部署一个nginx开始我们的k8s奇妙之旅。
新建yaml文件
vi app-v1.yaml
apiVersion: v1kind: Podmetadata: name: my-app-v1spec: containers: - name: my-nginx image: nginx:1.15.11 ports: - containerPort: 80
创建我们的第一个pod
kubectl create -f app-v1.yaml
查看我们刚刚建立的pod
kubectl get pod
接下来让我们解析下上述yaml文件的含义:
apiVersion,指定api版本,我们可以通过kubectl api-versions命令从我们的k8s集群中获取
kind,资源类型,这里我们创建的是一个Pod资源,这里资源类型可以是 Deployment、Job、Ingress、Service、ConfigMap 等(我们后续都会讲解)
metadata:包含了我们定义的 Pod 的一些 meta 信息,比如名称、namespace、标签等等
spec:包括一些 containers,storage,volumes,或者其他 Kubernetes 需要知道的参数,以及诸如是否在容器失败时重新启动容器的属性
请大家记住一个完整的yaml文件必须包含apiVersion、kind、metadata、spec这四个元素。
1.2.1 YAML文件的格式
它的基本语法规则如下:
大小写敏感
使用缩进表示层级关系
缩进时不允许使用Tab键,只允许使用空格。
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
#
表示注释,从这个字符一直到行尾,都会被解析器忽略。
在我们的 kubernetes 中,只需要两种结构类型就行了:
Lists
Maps
也就是说,你可能会遇到 Lists 的 Maps 和 Maps 的 Lists,等等。不过不用担心,你只要掌握了这两种结构也就可以了,其他更加复杂的我们暂不讨论。
Maps
首先我们来看看 Maps,我们都知道 Map 是字典,就是一个key:value
的键值对,Maps 可以让我们更加方便的去书写配置信息,例如:
---apiVersion: v1kind: Pod
第一行的---
是分隔符,是可选的,在单一文件中,可用连续三个连字号---
区分多个文件。这里我们可以看到,我们有两个键:kind
和 apiVersion
,他们对应的值分别是:v1 和Pod。上面的 YAML 文件转换成 JSON 格式的话,你肯定就容易明白了:
{ "apiVersion": "v1", "kind": "pod"}
我们再创建一个相对复杂一点的 YAML 文件,创建一个 KEY 对应的值不是字符串而是一个 Maps:
---apiVersion: v1kind: Podmetadata: name: kube100-site labels: app: web
上面的 YAML 文件,metadata 这个 KEY 对应的值就是一个 Maps 了,而且嵌套的 labels 这个 KEY 的值又是一个 Map,你可以根据你自己的情况进行多层嵌套。
上面我们也提到了 YAML 文件的语法规则,YAML 处理器是根据行缩进来知道内容之间的关联性的。比如我们上面的 YAML 文件,使用了两个空格作为缩进,空格的数量并不重要,但是得保持一致,并且至少要求一个空格(什么意思?就是你别一会缩进两个空格,一会缩进4个空格)。
我们可以看到 name 和 labels 是相同级别的缩进,所以 YAML 处理器就知道了他们属于同一个 MAP,而 app 是 labels 的值是因为 app 的缩进更大。
注意:在 YAML 文件中绝对不要使用 tab 键。
同样的,我们可以将上面的 YAML 文件转换成 JSON 文件:
{ "apiVersion": "v1", "kind": "Pod", "metadata": { "name": "kube100-site", "labels": { "app": "web" } }}
或许你对上面的 JSON 文件更熟悉,但是不得不承认 YAML 文件的语义化程度更高
Lists
Lists 就是列表,说白了就是数组,在 YAML 文件中我们可以这样定义:
args - Cat - Dog - Fish
可以有任何数量的项在列表中,每个项的定义以破折号(-)开头的,与父元素直接可以缩进一个空格。对应的 JSON 格式如下:
{ "args": ["Cat", "Dog", "Fish"]}
当然,list 的子项也可以是 Maps,Maps 的子项也可以是list,如下所示:
---apiVersion: v1kind: Podmetadata: name: kube100-site labels: app: webspec: containers: - name: front-end image: nginx ports: - containerPort: 80 - name: flaskapp-demo image: jcdemo/flaskapp ports: - containerPort: 5000
比如这个 YAML 文件,我们定义了一个叫 containers 的 List 对象,每个子项都由 name、image、ports 组成,每个 ports 都有一个 key 为 containerPort 的 Map 组成,同样的,我们可以转成如下 JSON 格式文件:
{ "apiVersion": "v1", "kind": "Pod", "metadata": { "name": "kube100-site", "labels": { "app": "web" } }, "spec": { "containers": [{ "name": "front-end", "image": "nginx", "ports": [{ "containerPort": 8080 }] }, { "name": "flaskapp-demo", "image": "jcdemo/flaskapp", "ports": [{ "containerPort": 5000 }] }] }}
是不是觉得用 JSON 格式的话文件明显比 YAML 文件更复杂了呢?
1.2.2 真正理解k8s中的pod
2.1 pod的概念
pod是k8s中最重要的概念,所以我们一定要先理解pod的概念。
pod是k8s中调度的最小单元,我们要清楚pod是一个逻辑上的概念,并不存在一个所谓的Pod隔离环境,也就是说,K8s 真正处理的还是宿主机操作系统上 Linux 容器的 Namespace 和 Cgroups,Pod其实是一组
共享了某些资源的容器。具体的说:Pod 里的所有容器,共享的是同一个Network Namespace,并且可以声明共享同一个Volume。
2.2 pod共享网络
比如说现在有一个 Pod,其中包含了一个容器 A 和一个容器 B,它们两个就要共享 Network Namespace。在 Kubernetes 里的解法是这样的:它会在每个 Pod 里,额外起一个 Infra container 小容器来共享整个 Pod 的 Network Namespace。
Docker的4种网络模式中有一种模式是container模式,它能够让很多容器共享一个网络名称空间, 具体的原理是先使用briage模式启动第一个容器, 之后启动的其他容器纷纷使用container模式将网络环境绑定到这第一个容器上。这样这些容器的网络就连接到了一起,他们互相可以使用localhost这种方式进行网络通信。
Infra container 是一个非常小的镜像,大概 100~200KB 左右,是一个汇编语言写的、永远处于“暂停”状态的容器。由于有了这样一个 Infra container 之后,其他所有容器都会通过 Join Namespace 的方式加入到 Infra container 的 Network Namespace 中。
所以说一个 Pod 里面的所有容器,它们看到的网络视图是完全一样的。即:它们看到的网络设备、IP地址、Mac地址等等,跟网络相关的信息,其实全是一份,这一份都来自于 Pod 第一次创建的这个 Infra container,这就是 Pod 解决网络共享的一个解法。
在 Pod 里面,一定有一个 IP 地址,是这个 Pod 的 Network Namespace 对应的地址,也是这个 Infra container 的 IP 地址。所以大家看到的都是一份,而其他所有网络资源,都是一个 Pod 一份,并且被 Pod 中的所有容器共享,这就是 Pod 的网络实现方式。
由于需要有一个相当于说中间的容器存在,所以整个 Pod 里面,必然是 Infra container 第一个启动,并且整个 Pod 的生命周期是等同于 Infra container 的生命周期的,与容器 A 和 B 是无关的。这也是为什么在 Kubernetes 里面,它是允许去单独更新 Pod 里的某一个镜像的,即:做这个操作,整个 Pod 不会重建,也不会重启,这是非常重要的一个设计。
注意:这种共享网络机制,可以让同一个pod中的容器访问使用localhost,同时也限制了同一个pod中的容器端口不能重复。
2.3 pod共享存储
Pod 共享存储就相对比较简单,现在有两个容器,一个是 Nginx,另外一个是php容器,在 Nginx 里放一些文件,让我能通过 Nginx 访问到,如果访问的是php文件,PHP-FastCGI也要能够访问到,所以我们需要去 share 这个目录,我 share 文件或者是 share 目录在 Pod 里面是非常简单的,实际上就是把 volume 变成了 Pod level。然后所有容器,就是所有同属于一个 Pod 的容器,他们共享所有的 volume。
1.2 部署Nginx+PHP
我们改造一下我们的第一个pod,验证一下pod中的容器是共享网络的和如何实现共享存储。
新建yaml文件
vi app-v2.yaml
apiVersion: v1kind: Podmetadata: name: my-app-v2spec: containers: - name: my-nginx image: nginx:1.15.11 ports: - containerPort: 8080 volumeMounts: - name: app-www mountPath: /usr/share/nginx/html - name: my-php image: php:7.2-fpm ports: - containerPort: 9000 volumeMounts: - name: app-www mountPath: /var/www/html volumes: - name: app-www emptyDir: {}
创建我们新的pod
kubectl create -f app-v2.yaml
查看我们新建的pod的ip地址和所在的节点
kubectl get pod -o wide
在pod所在的节点创建测试的PHP文件和Nginx配置文件
# 创建data文件夹mkdir datavi index.php# index.php内容如下<?php echo "this is php";vi index.html# 内容如下this is html# 创建默认的default.conf文件vi default.conf# 内容如下 注意我们这里fastcgi_pass用了localhostserver { listen 80 default; index index.php index.html index.htm; server_name localhost; root /usr/share/nginx/html; location ~ \.php { include fastcgi_params; fastcgi_pass localhost:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name; }}
注意:上述fastcgi_pass的值是 localhost:9000
把测试的文件拷贝到容器中
# 查看nginx容器的名字docker psdocker cp ./index.php [nginx容器的名称]:/usr/share/nginx/htmldocker cp ./default.conf [nginx容器的名称]:/etc/nginx/conf.d
验证
# 访问php文件curl my-app-v2容器所在pod的id:80/index.php# 访问成功,证明一个pod中的所有容器网络是共享的,可以用localhost访问到# 查看php容器中的/var/www/html是否有我们刚上传的index.php文件docker exec -it 你的php容器的名字 /bin/bash# 进入容器后执行cd /var/www/htmlls# 我们发现了我们刚上传到此目录的index.php文件,所以nginx的/usr/share/nginx/html目录和PHP的/var/www/html目录通过volume:emptyDir已经完成了共享
2.1 给pop挂载目录的方式
app-v2.yaml配置文件在最下面定义了一个叫“app-www”的volume,然后上面的两个容器来使用它就好了,其实volumes这个地方有三种选择
# 方式1:volumes: - name: app-logs emptyDir: {} # 方式2:volumes: - name: app-logs hostPth: path: "/data" # 方式3: volumes: - name: app-logs gcePersistenDisk: pdName: my-data-disk //my-data-disk需要先创建好 fsType: ext4
emptyDir:是Pod分配到Node后创建的,他的初始内容为空,pod在Node上移除以后也就被销毁了。
hostPath:是挂载到宿主机上的目录,比较适用于需要永久保存的数据
gcePersistenDisk:表示使用谷歌公有云提供的磁盘创建my-data-disk:gcloud compute disks create --size=500GB --zone=us-centrall-a my-data-disk
我们在刚才验证的时候,是通过docker cp拷贝文件到容器中的,这种操作只是为了验证volume:emptyDir共享存储,接下来我们再来看看如何用hostPath挂载目录到宿主机上
把刚才的index.php和default.conf分别放到/data/www和/data/conf.d目录下面,然后分别scp到各个节点,因为我们创建pod的时候,不一定创建到哪个node上(后面会讲解指定node创建pod)。
在/data中新建yaml文件
vi app-v3.yaml
apiVersion: v1kind: Podmetadata: name: my-app-v3spec: containers: - name: my-nginx image: nginx:1.15.11 ports: - containerPort: 8080 volumeMounts: - name: app-www mountPath: /usr/share/nginx/html - name: app-conf mountPath: /etc/nginx/conf.d - name: my-php image: php:7.2-fpm ports: - containerPort: 9000 volumeMounts: - name: app-www mountPath: /var/www/html volumes: - name: app-www hostPath: path: /data/www - name: app-conf hostPath: path: /data/conf.d
创建我们新的pod
kubectl create -f app-v3.yaml
查看新pod的ip地址
kubectl get pod -o wide
验证
curl [my-app-v3容器所在pod的id]:80/index.php
到现在为止您是不是会有很多疑惑?
1、为什么用curl来验证而不是用浏览器直接访问验证?
2、如果node节点多了,每个pod容器都要用volumes:hostPath来挂载配置文件吗?
由于篇幅有限,这些疑问我会在下一章节中持续讲解,欢迎大家持续关注,也欢迎大家点赞和转发。
推荐阅读:
推荐一款爱不释手的文本编辑器Typora
如何解决Redis的缓存穿透、缓存雪崩和缓存击穿
架构师必须了解的日志管理ELK
初识LVS负载均衡
API接口安全您做了哪些?
如何提高您的MySQL性能
Redis从入门到高可用分布式实战(一)
让我们一起开启Docker的大门
带您一小时玩转Docker
更多推荐
所有评论(0)