千家信息网

如何进行minikube部署本地镜像实践与k8s网络架构分析

发表于:2024-10-23 作者:千家信息网编辑
千家信息网最后更新 2024年10月23日,如何进行minikube部署本地镜像实践与k8s网络架构分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。在 windows10 的 W
千家信息网最后更新 2024年10月23日如何进行minikube部署本地镜像实践与k8s网络架构分析

如何进行minikube部署本地镜像实践与k8s网络架构分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

在 windows10 的 WSL2 里用minikube搭建了一个k8s环境,但是每次拉取镜像都很慢甚至失败(原因大家都懂的), 本文的方案的原理是, 先将镜像在宿主机上f-q拉取到本地, 再由minikube 虚机中的k8s 来拉取本地镜像, 这样即可解决之前的拉取镜像失败,也可提升拉取镜像的速度;

两种方案
把私有镜像仓库docker registry 搭建在宿主机上, k8s从本地宿主机上拉取镜像;
把本地镜像推送到minikube的私有镜像仓库上, k8s从minikube的私有镜像仓库(k8s的本地私有镜像仓库)拉取镜像;

1、构建一个镜像

一个完整镜像通常包含应用本身和操作系统,当然还包含需要的依赖软件。

首先准备一个应用。新建一个本文文件,起名叫 app.py,写入下面的内容,实现一个简单的web应用:

from flask import Flaskimport socketimport osapp = Flask(__name__)@app.route('/')def hello():    html = "

Hello {name}!

" \ "主机名: {hostname}
" return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())if __name__ == "__main__": app.run(host='0.0.0.0', port=8082)

在这段代码中,使用 Flask 框架启动了一个 Web 服务器,而它唯一的功能是:如果当前环境中有"NAME"这个环境变量,就把它打印在"Hello"后,否则就打印"Hello world",最后再打印出当前环境的 hostname。
这个应用的依赖文件requirements.txt存在于与app.py同级目录中,内容是:

$ cat requirements.txtFlask

将这样一个应用在容器中跑起来,需要制作一个容器镜像。Docker使用Dockerfile文件来描述镜像的构建过程。在本文中,Dockerfile内容定义如下:

# FROM指令指定了基础镜像是python:3.6-alpine,这个基础镜像包含了Alpine Linux操作系统和python3.6FROM python:3.6-alpine# WORKDIR指令将工作目录切换为 /appWORKDIR /app# ADD指令将当前目录下的所有内容(app.py、requirements.txt)复制到镜像的 /app 目录下ADD . /app# RUN指令运行 pip 命令安装依赖RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt# EXPOSE指令暴露允许被外界访问的8082端口EXPOSE 8082# ENV指令设置环境变量NAMEENV NAME World# CMD指令设置容器内进程为:python app.py,即:这个 Python 应用的启动命令CMD ["python", "app.py"]

这个Dockerfile中用到了很多指令,把包括FROM、WORKDIR、ADD、RUN、EXPOSE、ENV和CMD。指令的具体含义已经以注释的方式写在了Dockerfile中,大家可以查看。通常我们构建镜像时都会依赖一个基础镜像,基础镜像中包含了一些基础信息,我们依赖基础构建出来的新镜像将包含基础镜像中的内容。

需要再详细介绍一下CMD指令。CMD指定了python app.py为这个容器启动后执行的进程。CMD ["python", "app.py"] 等价于在容器中执行 "python app.py"。

另外,在使用 Dockerfile 时,还有一种 ENTRYPOINT 指令。它和 CMD 都是 Docker 容器进程启动所必需的参数,完整执行格式是:"ENTRYPOINT CMD"。

默认情况下,Docker 会为你提供一个隐含的 ENTRYPOINT,即:/bin/sh -c。所以,在不指定 ENTRYPOINT 时,比如在我们这个例子里,实际上运行在容器里的完整进程是:/bin/sh -c "python app.py",即 CMD 的内容就是 ENTRYPOINT 的参数。正是基于这样的原理,Docker 容器的启动进程为实际为 ENTRYPOINT,而不是 CMD。

需要注意的是,Dockerfile 里的指令并不都是只在容器内部的操作。就比如 ADD,它指的是把当前目录(即 Dockerfile 所在的目录)里的文件,复制到指定容器内的目录当中。

更多能在Dockerfile中使用的指令,可以参考官方文档:

https://docs.docker.com/engine/reference/builder/#dockerfile-reference。

根据前面的描述,现在我们的整个应用的目录结构应该如下这样:

$ lsDockerfile  app.py   requirements.txt

执行下面的指令可以构建镜像:

$ docker build  -f /path/to/Dockerfile -t helloworld .Sending build context to Docker daemon  4.608kBStep 1/7 : FROM python:3.6-alpine ---> 5e7f84829665Step 2/7 : WORKDIR /app ---> Using cache ---> dbb4a00a8f68Step 3/7 : ADD . /app ---> fd33ac91c6c7Step 4/7 : RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt ---> Running in 6b82e863d802Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simpleCollecting Flask  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/f2/28/2a03252dfb9ebf377f40fba6a7841b47083260bf8bd8e737b0c6952df83f/Flask-1.1.2-py2.py3-none-any.whl (94 kB)Collecting click>=5.1  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/dd/c0/4d8f43a9b16e289f36478422031b8a63b54b6ac3b1ba605d602f10dd54d6/click-7.1.1-py2.py3-none-any.whl (82 kB)Collecting Jinja2>=2.10.1  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/27/24/4f35961e5c669e96f6559760042a55b9bcfcdb82b9bdb3c8753dbe042e35/Jinja2-2.11.1-py2.py3-none-any.whl (126 kB)Collecting itsdangerous>=0.24  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)Collecting Werkzeug>=0.15  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB)Collecting MarkupSafe>=0.23  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz (19 kB)Building wheels for collected packages: MarkupSafe  Building wheel for MarkupSafe (setup.py): started  Building wheel for MarkupSafe (setup.py): finished with status 'done'  Created wheel for MarkupSafe: filename=MarkupSafe-1.1.1-py3-none-any.whl size=12629 sha256=1f965945354a52423078c573deb1a8116965e67b2467c3640264d7f02058b06d  Stored in directory: /root/.cache/pip/wheels/06/e7/1e/6e3a2c1ef63240ab6ae2761b5c012b5a4d38e448725566eb3dSuccessfully built MarkupSafeInstalling collected packages: click, MarkupSafe, Jinja2, itsdangerous, Werkzeug, FlaskSuccessfully installed Flask-1.1.2 Jinja2-2.11.1 MarkupSafe-1.1.1 Werkzeug-1.0.1 click-7.1.1 itsdangerous-1.1.0Removing intermediate container 6b82e863d802 ---> d672a00c1a2fStep 5/7 : EXPOSE 8083 ---> Running in b9b2338da3f3Removing intermediate container b9b2338da3f3 ---> e91da5a22e20Step 6/7 : ENV NAME World ---> Running in d7e5d19f3eedRemoving intermediate container d7e5d19f3eed ---> 4f959f34d486Step 7/7 : CMD ["python", "app.py"] ---> Running in 99a97bedace0Removing intermediate container 99a97bedace0 ---> 3bc3e537ebb7Successfully built 3bc3e537ebb7Successfully tagged helloworld:latest

其中,-t 的作用是给这个镜像加一个 Tag,即:起一个好听的名字。docker build 会自动加载当前目录下的 Dockerfile 文件,然后按照顺序执行Dockerfile文件中的指令。

上面的命令执行完成后,就生成了一个镜像。可以通过下面的指令查看:

$ docker image lsREPOSITORY          TAG                 IMAGE ID            CREATED             SIZEhelloworld          latest              3bc3e537ebb7        2 minutes ago       103MB

还可以通过 docker inspect helloworld:latest 查看镜像的元信息。

元信息中包含了镜像的全部信息,包括镜像的tag,构建时间,环境变量等。

如果镜像不再需要了,可以通过docker image rm删除镜像。

有了镜像,就可以通过下面的指令来运行镜像得到容器了。

$ docker run -p 8082:8082 helloworld * Serving Flask app "app" (lazy loading) * Environment: production   WARNING: This is a development server. Do not use it in a production deployment.   Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:8082/ (Press CTRL+C to quit)

上面命令中,镜像名 helloworld 后面,什么都不用写,因为在 Dockerfile 中已经指定了 CMD。否则,我就得把进程的启动命令加在后面:

$ docker run -p 8082:8082 helloworld python app.py

从现在看,容器已经正确启动,我们使用curl命令通过宿主机的IP和端口号,来访问容器中的web应用。

$ curl http://0.0.0.0:8082/

Hello World!

主机名: 59b607239c3a

从输出中可以看到容器的ID,容器是基于哪个镜像的启动的,容器中的进程,容器的启动时间及端口映射情况,以及容器的名字。

使用docker inspect 59b607239c3a命令,可以查看容器的元数据,内容非常丰富。

2、k8s从宿主机私有镜像仓库中拉取镜像

2.1 搭建宿主机私有镜像仓库;sudo docker pull registrysudo docker run -d -p 5000:5000 -v $(pwd):/var/lib/registry --restart always --name registry registry:22.2 验证私有镜像仓库curl http://127.0.0.1:5000/v2/_catalog2.3 推送镜像到私有镜像仓库重启docker服务使配置生效: systemctl restart docker172.19.242.79 是宿主机ipmac 配置路径: 工具栏-> docker -> Preferences -> Daemon -> basic -> Insecure registries 加上一行: 172.19.242.79:5000sudo vim /etc/docker/daemon.json  "insecure-registries" : [    "172.19.242.79:5000"  ],  "debug" : true2.4 推送到镜像仓库sudo docker tag helloworld 172.19.242.79:5000/flaskhelloworld  # 标记本地镜像,将其归入某一仓库sudo docker push 172.19.242.79:5000/flaskhelloworld   # 最开始 docker build -t 直接打入指定(远程)仓库可省去上一步curl -X GET 172.19.242.79:5000/v2/_catalog2.5 配置minikube 并重启为了使得minikube 虚机中的k8s 能拉取到宿主机私有镜像 需要上述两项配置 -registry-mirror 和 -insecure-registrysudo minikube start --driver=none --insecure-registry="172.19.242.79:5000"   --image-mirror-country cn \        --iso-url=https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.15.1.iso  \        --registry-mirror=https://你注册的aliyun加速地址.mirror.aliyuncs.com2.6 部署镜像与开放服务接口sudo kubectl create deployment flaskhelloworld --image=172.19.242.79:5000/flaskhelloworldsudo kubectl expose deployment flaskhelloworld --type=LoadBalancer --port=6789 --target-port=8082 sudo minikube service flaskhelloworld --url#sudo kubectl port-forward flaskhelloworld-6b7695c6df-5hclc 8888:8082                #sudo kubectl create -f flaskhelloworld.yaml#sudo kubectl describe pod flaskhelloworld-pod#sudo kubectl port-forward flaskhelloworld-pod 8888:8080#sudo kubectl run flaskhelloworld --image=172.19.242.79:5000/flaskhelloworld --port 3000#sudo kubectl expose pod flaskhelloworld --name flaskhelloworld-http --type=LoadBalancer#sudo minikube service flaskhelloworld-http

3、k8s 中 pod、service、ingress 网络架构分析

sudo minikube service flaskhelloworld|-----------|-----------------|-------------|----------------------------|| NAMESPACE |      NAME       | TARGET PORT |            URL             ||-----------|-----------------|-------------|----------------------------|| default   | flaskhelloworld |        6789 | http://172.19.242.79:30792 ||-----------|-----------------|-------------|----------------------------|????  正通过默认浏览器打开服务 default/flaskhelloworld...????  http://172.19.242.79:30792

每次访问的主机信息不一样,是因为我们 deployments 后,执行了

kubectl scale -n default deployment flaskhelloworld --replicas=3

集群有3个pod

在Kubernetes中,部署一个Deployment是无法对外进行访问的,就是别的应用程序要想访问部署的Deployment,找不到该怎么去访问,为什么这么讲,因为Deployment一般都是多副本部署的,有可能会分布在不同的节点之上,而且重建Pod IP也会变,重新发布一下也会改变,所以没有办法去固定去访问哪个Pod,即使固定了,其他的Pod也访问不了,要想做到多个Pod都去提供服务,前面就必须要加一个负载均衡,提供一个访问入口,只有访问这个统一入口,才能转发到后端多个Pod上,只要访问这个Cluster IP就能转发到后端的Pod上。

Service

  • Service定义了Pod的逻辑集合和访问这个集合的策略

  • Service的引入为解决Pod的动态变化,提供了服务发现和负载均衡

  • 使用CoreDNS解析Service名称

sudo kubectl get servicesNAME                    TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGEflaskhelloworld         LoadBalancer   10.98.106.240         6789:30792/TCP               31mflink-jobmanager        ClusterIP      10.100.169.253           6123/TCP,6124/TCP,8081/TCP   7d12hflink-jobmanager-rest   NodePort       10.103.71.37             8081:30424/TCP               7d12hkubernetes              ClusterIP      10.96.0.1                443/TCP                      7d12h

因此,我们也可以用集群IP来访问:

services 暴露出去之后,也就是需要让用户去访问,比如搭建一个电商网站,让用户去访问,Ingress相对于Service,是一个互补的状态,Service主要提供了集群内部的访问,也可以暴露一个TCP/UDP的端口,而Ingress主要是一个7层的转发,也就是提供一个统一的入口,只要访问Ingress Controller,就能帮你转发你部署所有的项目,也就是所有的项目都使用域名去访问。

为了进一步了解网络架构,我们也可以直接用 pod ip + port 来访问

sudo kubectl get endpoints serviceName # 查看 Service backend pods(在 Kubernetes 对应多个 endpoint)

看完上述内容,你们掌握如何进行minikube部署本地镜像实践与k8s网络架构分析的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

0