Mac:docker无法映射?这个锅我不背
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
目录
背景
本篇文章作为k8s学习系列的第一篇,讲一讲在搭建环境遇到的各种问题。
通读完本篇,你将学到:
-
docker网络相关的知识
-
一个简单反向代理的应用集群搭建
-
排查容器相关问题的一般性思路
本篇实验环境如下:
-
Mac
-
Docker desktop for mac
-
kuberetes节点(minikube、kubeadm等)
目标
搭建一个集群,其大致模型如下:
目标是访问http://127.0.0.1
可以直接访问到WordPress网站。
步骤
第一步:部署MariaDB
准备yml文件 maria.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: maria-cm
data:
DATABASE: 'db'
USER: 'wp'
PASSWORD: '123'
ROOT_PASSWORD: '123'
---
apiVersion: v1
kind: Pod
metadata:
name: maria-pod
labels:
app: wordpress
role: database
spec:
containers:
- image: mariadb:10
name: maria
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
envFrom:
- prefix: 'MARIADB_'
configMapRef:
name: maria-cm
执行部署命令
# kubectl apply -y maria.yml
执行命令,查看pod的IP
# kubectl get pod -o wide
22-08-03 - 22:32:10
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
maria-pod 1/1 Running 0 47s 172.17.0.3 minikube <none> <none>
记住这个172.17.0.3
,在第二步的时候需要用到
第二步:部署WordPress的Pod
准备yml文件 wordpress-pod.yml
注意:上面的
172.17.0.3
需要填在yml的对应位置上。
apiVersion: v1
kind: ConfigMap
metadata:
name: wp-cm
data:
HOST: '172.17.0.3'
USER: 'wp'
PASSWORD: '123'
NAME: 'db'
---
apiVersion: v1
kind: Pod
metadata:
name: wp-pod
labels:
app: wordpress
role: website
spec:
containers:
- image: wordpress:5
name: wp-pod
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
envFrom:
- prefix: 'WORDPRESS_DB_'
configMapRef:
name: wp-cm
执行部署命令
# kubectl apply -f wordpress-pod.yml 22-08-03 - 22:37:36
configmap/wp-cm created
pod/wp-pod created
# kubectl get pod -o wide :( 1 22-08-03 - 22:38:35
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
maria-pod 1/1 Running 0 6m36s 172.17.0.3 minikube <none> <none>
wp-pod 1/1 Running 0 59s 172.17.0.4 minikube <none> <none>
第三步:为 WordPress Pod 映射端口号,让它在集群外可见
因为 Pod 都是运行在 Kubernetes 内部的私有网段里的,外界无法直接访问,想要对外暴露服务,需要使用一个专门的 kubectl port-forward 命令,它专门负责把本机的端口映射到在目标对象的端口号,经常用于 Kubernetes 的临时调试和测试。
# kubectl port-forward wp-pod 8080:80 &
第四步:创建反向代理的 Nginx
这是因为 WordPress 网站使用了 URL 重定向,直接使用“8080”会导致跳转故障,所以为了让网站正常工作,我们还应该在 Kubernetes 之外启动 Nginx 反向代理,保证外界看到的仍然是“80”端口号。
准备proxy.conf
server {
listen 80;
default_type text/html;
location / {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8080;
}
}
docker启动nginx容器进行反向代理
docker run -d --rm \
--net=host \
-v `pwd`/proxy.conf:/etc/nginx/conf.d/default.conf \
nginx:alpine
结果
声明:本次实验流程linux运行无异常,对Mac或者Windows有异常,需要重新调试。
docker run -d --rm \ 22-08-03 - 22:38:46
--net=host \
-v `pwd`/proxy.conf:/etc/nginx/conf.d/default.conf \
nginx:alpine
17b6a07e984106390aa25b2d9081a330b515794db8354f1b3bd57e2bcb0752dd
访问http://127.0.0.1
不行了!!
排查
分为几个步骤排查
整体的数据流向图(网络向)
端口转发
访问 http://127.0.0.1:8080
,观察是否有动静
如果可以看到页面
说明wordpress → mariadb的链路正常
本机8080端口转发wordpress pod 80端口正常
网络链路的最后两步骤正常
Nginx转发
接下来排查Nginx转发是否正常
这个步骤分为两个部分
第一部分,查看配置
# docker exec -it 17 sh
:( 255 22-08-03 - 23:04:45
# cat /etc/nginx/conf.d/default.conf
server {
listen 80;
default_type text/html;
location / {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8080;
}
}
配置文件和我们的预期都没有太大的差别
接下来我们就要测试网络是否通畅
在容器中curl 我们想要去的地方
结果发现,并没有返回nginx相关的东西
说明:127.0.0.1 并没有访问到宿主机
问题一:在容器中怎么访问到宿主机
按照道理说,我们在启动容器的时候,使用了-net=host
的选项,理论上容器和宿主机共用同一个网络,共用同一套端口,为什么127.0.0.1 无法访问到宿主机?
第二部分:查看日志
问题二:为什么主机的80端口无法绑定到容器的nginx上?
查找网络资料发现如下:
host.docker.internal
可以从容器上访问宿主机
针对问题一:
修改proxy.conf
server {
listen 80;
default_type text/html;
location / {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_pass http://host.docker.internal:8080;
}
}
针对问题二:
修改启动命令
docker run -d --rm -p 80:80 -v `pwd`/proxy.conf:/etc/nginx/conf.d/default.conf nginx:alpine 22-08-03 - 23:20:14
0ecc8743db2737080e4854563c133018371dd20d27151a136b64070163fee23a
知识点
docker底层使用原生的系统指令
使用了Cgroup,Namespace,UFS等技术做了隔离。
本质上启动的容器只是一个个被隔离的进程。
这也是docke高效运行的原因
但是在Mac和Window上,使用Desktop 软件
由于不是docker运行的原生环境
本质上这些软件就是一个虚拟机
把linux上的指令翻译成对应平台上的指令
在这个问题中的网络模型中,需要再加一层
我们使用 -net=host
启动容器,本质上是绑定了Docker容器和Docker Desktop这个虚拟机共用一个网络和端口环境。而Docker Desktop提供的gateway.docker.internal
才是作用宿主机和Docker Desktop网络环境的关键,并不受到-net=host
的控制。
所以我们需要使用 -p 来进行端口映射,让Docker Desktop来帮我们处理 宿主机 port1
端口到Docker Desktop端口port2
上,Docker Desktop端口port2
到容器端口port2
上,这个两层映射。这个过程对我们使用者来说是透明的,无需关心的。