Kubernetes Harbor部署、Service与服务发现详解
Harbor的部署注意事项
使用的是老师的docker安装包进行部署
-
重新开机后要执行:
bashdocker-compose up -d -
所有k8s节点都要进行harbor的证书配置
导入镜像到harbor流程
bash
# 1. 加载镜像到本地docker
docker load -i oldboyedu-mysql-v8.0.36-oracle.tar.gz
# 2. 为镜像打标签,格式为:harbor地址/项目名/镜像名:标签
docker tag mysql:8.0.36-oracle harbor250.oldboyedu.com/oldboyedu-db/mysql:8.0.36-oracle
# 3. 推送到harbor仓库
docker push harbor250.oldboyedu.com/oldboyedu-db/mysql:8.0.36-oracle
故障排查技巧三种方式
-
查看log日志:
bashkubectl logs <pod_name> -
查看pod详细描述信息:
bashkubectl describe pod <pod_name> -
进入容器内部排查:
bashkubectl exec <pod_name> -- <command> <args>
资源清单------MySQL
yaml
[root@master231 pods]# cat 06-pods-mysql.yaml
apiVersion: v1
kind: Pod
metadata:
name: oldboyedu-mysql
labels:
app: xiuxian
version: v1
spec:
# 重启策略默认是always
restartPolicy: Always
containers:
- name: c1
image: harbor250.oldboyedu.com/oldboyedu-db/mysql:8.0.36-oracle
# 向容器传递参数:指定引擎
args:
- --character-set-server=utf8
- --collation-server=utf8_bin
- --default-authentication-plugin=mysql_native_password
# 向容器传递环境变量,必须做,指定创建的数据库,用户名,密码
env:
# 变量的名称
# 可以允许空密码登入
- name: MYSQL_ALLOW_EMPTY_PASSWORD
# 指定变量的值:意思创建了数据库叫wordpress,并创建了用户名密码
value: "yes"
- name: MYSQL_DATABASE
value: "wordpress"
- name: MYSQL_USER
value: linux99
- name: MYSQL_PASSWORD
value: oldboyedu
测试验证:
bash
kubectl exec -it oldboyedu-mysql -- mysql wordpress
暴露到k8s集群外部的方法
- hostNetwork
- hostPort
- port-forward
- nodeport
暴露K8S的Pod到集群外部之hostNetwork
yaml
[root@master231 pods]# cat 07-pods-hostNetwork.yaml
apiVersion: v1
kind: Pod
metadata:
name: xiuxian
spec:
# 使用宿主机网络
hostNetwork: true
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/yinzhengjie-k8s/apps:v1
此时发现IP变成了物理网络,访问:
http://10.0.0.233/
暴露K8S的Pod到集群外部之hostPort
yaml
[root@master231 pods]# cat 08-pods-hostPort.yaml
apiVersion: v1
kind: Pod
metadata:
name: xiuxian-001
spec:
# 指定节点调度,节点的名称必须在etcd数据库中有记录,可以使用"kubectl get no"进行查看。
nodeName: worker232 # 也可以不指定,会随机给节点进行调度
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/yinzhengjie-k8s/apps:v2
# 对外暴露服务,有点类似于: docker run -p 90:80 ...
ports:
# 容器对外暴露的端口
- containerPort: 80
# 将宿主机的某个端口转发到容器的端口,访问直接物理机ip+90
hostPort: 90
测试验证:由于调度到worker232节点,因此可以直接使用该节点的IP地址和端口进行访问。
http://10.0.0.232:90/
暴露K8S的Pod到集群外部之port-forward
正常pod资源清单:
yaml
[root@master231 pods]# cat 01-pods-single-xiuxian.yaml
apiVersion: v1
kind: Pod
metadata:
name: xixi
spec:
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/yinzhengjie-k8s/apps:v2
新开一个终端添加转发规则:
bash
# --address 0.0.0.0:监听所有网络接口。只能当前节点可以访问
# xixi:Pod 名称(或 service/xxx 服务名称)。
# 99:80:将本地的 99 端口转发到 Pod 的 80 端口
[root@master231 pods]# kubectl port-forward --address 0.0.0.0 xixi 99:80
访问测试:
http://10.0.0.231:99/
案例------WordPress对外暴露
需求:
- 部署MySQL到worker232节点;
- 部署wordpress业务到worker233节点并让K8S集群能够正常访问;
资源清单如下:
yaml
[root@master231 pods]# cat 09-pods-wordpress.yaml
apiVersion: v1
kind: Pod
metadata:
name: db
spec:
# 使用宿主机232部署,并且使用该网络
nodeName: worker232
hostNetwork: true
containers:
- name: db
image: harbor250.oldboyedu.com/oldboyedu-db/mysql:8.0.36-oracle
args:
- --character-set-server=utf8
- --collation-server=utf8_bin
- --default-authentication-plugin=mysql_native_password
env:
- name: MYSQL_ALLOW_EMPTY_PASSWORD
value: "yes"
- name: MYSQL_DATABASE
value: "wordpress"
- name: MYSQL_USER
value: linux99
- name: MYSQL_PASSWORD
value: oldboyedu
---
apiVersion: v1
kind: Pod
metadata:
name: wp
spec:
# 指定宿主机233部署wordpress,但此时没有指定访问方式
nodeName: worker233
containers:
- name: wp
image: harbor250.oldboyedu.com/oldboyedu-wp/wordpress:6.7.1-php8.1-apache
env:
- name: WORDPRESS_DB_HOST
value: "10.0.0.232"
- name: WORDPRESS_DB_NAME
value: "wordpress"
- name: WORDPRESS_DB_USER
value: linux99
- name: WORDPRESS_DB_PASSWORD
value: oldboyedu
# 传递变量,数据库宿主机的IP地址,数据库的库,用户名密码
暴露WordPress业务:
bash
[root@master231 pods]# kubectl port-forward --address 0.0.0.0 wp 80:80
# 只在当前k8s节点都可以通过80端口进行访问
访问测试:
http://10.0.0.231/wp-admin/install.php
用户密码: admin 1
案例------ES部署到k8s(使用hostPort)
资源清单:
yaml
[root@master231 pods]# cat 10-pods-es.yaml
apiVersion: v1
kind: Pod
metadata:
name: oldboyedu-es
spec:
containers:
- name: es
image: harbor250.oldboyedu.com/oldboyedu-elasticstack/elasticsearch:7.17.25
ports:
# 宿主机9200,容器9200。访问的时候直接访问该物理机的ip+9200
- containerPort: 9200
name: http
hostPort: 9200
- containerPort: 9300
name: tcp
env:
- name: discovery.type
value: "single-node"
# 单点部署
Service类型及验证服务发现和负载均衡案例
Service简介
- Service是K8S集群的一个资源,底层基于标签来关联Pod。访问Service时可以关联到相应的Pod。
- Service为Pod提供统一的访问入口,当Pod的IP发生变化时,会自动关联到变化后的IP。
- 简而言之,Service为Pod提供了负载均衡和服务发现。
为什么需要service?
场景:现在起了三个rc副本,然后把它删除会发现:
- 删除Pod后会自动拉起,但是Pod的IP地址会发生变化!
- 这样会导致不小心删除和重启都会IP变化,所以要使用service服务通过标签进行IP的关联。
Service类型
yaml
# 指定Service的类型,有效值为: ExternalName, ClusterIP, NodePort, and LoadBalancer。
# ClusterIP:
# 该Service资源只能被K8S集群内部进行访问。一般用于K8S集群Pod互相访问。
# NodePort:
# 在ClusterIP基础之上,在K8S所有的worker节点添加了端口映射规则。
# 换句话说,就是你访问K8S集群任意一个worker的某个特定端口,则会将其请求转发到集群内部的ClusterIP。
# LoadBalancer:
# 一般情况下用在云厂商环境,如果线下想要使用该类型,则可以部署相应的组件来实现此功能。
# 该类型原生不支持,需要部署第三方组件。
# ExternalName:
# 将K8S集群外部的某个服务映射到K8S集群内部的Service,底层采用CNAME技术实现。
# 如果不指定Service类型,不定义该字段则默认是ClusterIP。
资源清单:使用service连接rc的pod
使得无论rc的IP怎么变化,都能通过service的IP进行访问。
yaml
[root@master231 services]# cat 01-svc-clusterIP.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian
spec:
# 指定Service的类型,有效值为: ExternalName, ClusterIP, NodePort, and LoadBalancer。
# ClusterIP:
# 该Service资源只能被K8S集群内部进行访问。一般用于K8S集群Pod互相访问。
# NodePort:
# 在ClusterIP基础之上,在K8S所有的worker节点添加了端口映射规则。
# 换句话说,就是你访问K8S集群任意一个worker的某个特定端口,则会将其请求转发到集群内部的ClusterIP。
# LoadBalancer:
# 一般情况下用在云厂商环境,如果线下想要使用该类型,则可以部署相应的组件来实现此功能。
# 该类型原生不支持,需要部署第三方组件。
# ExternalName:
# 将K8S集群外部的某个服务映射到K8S集群内部的Service,底层采用CNAME技术实现。
# 如果不指定Service类型,不定义该字段则默认是ClusterIP。
type: ClusterIP
# 标签选择器,用来关联Pod
selector:
app: xiuxian
# 配置端口映射
ports:
# 指定是Service端口号
- port: 90
# 指定后端容器的端口
targetPort: 80
访问测试: service的IP+端口
bash
curl 10.200.199.151:90
案例------kibana连接ES集群并连接filebeat
此时ES使用ClusterIP,然而kibana和filebeat使用的是NodePort
编写资源清单:一个service对应一个pod
yaml
[root@master231 pods]# cat 11-pods-efk.yaml
apiVersion: v1
kind: Pod
metadata:
name: oldboyedu-es
labels:
app: es7
spec:
containers:
- name: es
image: harbor250.oldboyedu.com/oldboyedu-elasticstack/elasticsearch:7.17.25
ports:
- containerPort: 9200
name: http
- containerPort: 9300
name: tcp
env:
- name: discovery.type
value: "single-node"
---
apiVersion: v1
kind: Service
metadata:
name: svc-es7
spec:
type: ClusterIP
# 指定Service的IP地址,注意自定义时要和你集群的svc网段一致(10.200.0.0/16)
clusterIP: 10.200.0.92
selector:
app: es7
ports:
- port: 9200
targetPort: http
---
apiVersion: v1
kind: Pod
metadata:
name: oldboyedu-kibana
labels:
app: kibana
spec:
containers:
- name: kibana
image: harbor250.oldboyedu.com/oldboyedu-elasticstack/kibana:7.17.25
ports:
- containerPort: 5601
name: webui
env:
- name: ELASTICSEARCH_HOSTS
value: "http://10.200.0.92:9200"
- name: I18N_LOCALE
value: "zh-CN"
---
apiVersion: v1
kind: Service
metadata:
name: svc-kibana
spec:
# 向外暴露端口
type: NodePort
selector:
app: kibana
ports:
- port: 5601
targetPort: webui
nodePort: 30090
---
apiVersion: v1
kind: Pod
metadata:
name: oldboyedu-filebeat
labels:
app: filebeat
spec:
containers:
- name: filebeat
image: harbor250.oldboyedu.com/oldboyedu-elasticstack/filebeat:7.17.25
ports:
- containerPort: 8888
name: tcp
---
apiVersion: v1
kind: Service
metadata:
name: svc-filebeat
spec:
type: NodePort
selector:
app: filebeat
ports:
- port: 8888
targetPort: tcp
nodePort: 30088
进行测试
bash
# 进入filebeat容器
[root@master231 pods]# kubectl exec -it oldboyedu-filebeat -- bash
# 创建配置文件
filebeat@oldboyedu-filebeat:~$ cat > /tmp/tcp-to-es.yaml <<EOF
filebeat.inputs:
- type: tcp
host: "0.0.0.0:8888"
output.elasticsearch:
hosts: ["http://10.200.0.92:9200"]
index: oldboyedu-linux99-tcp
setup.ilm.enabled: false
setup.template.name: "oldboyedu-linux99"
setup.template.pattern: "oldboyedu-linux99*"
setup.template.overwrite: false
setup.template.settings:
index.number_of_shards: 3
index.number_of_replicas: 0
EOF
# 启动filebeat
filebeat@oldboyedu-filebeat:~$ filebeat -e -c /tmp/tcp-to-es.yaml --path.data=/tmp/xixi
发送测试数据:
bash
[root@master231 services]# echo www.oldboyedu.com | nc 10.0.0.233 30088
注意:
- 命令
nc 10.0.0.233 30088的作用是:通过节点物理IP和NodePort,将测试数据发送到Filebeat的TCP输入端口(8888),最终由Filebeat转发到Elasticsearch。 host: "0.0.0.0:8888"是为了让Filebeat在容器内监听所有网络接口,确保外部(通过NodePort 30088或Service)的TCP数据能被正确接收并转发到Elasticsearch。
查看kibana的webUI:
http://10.0.0.232:30090/app/management/data/index_management/indices
关键字段解析
yaml
ports:
- port: 5601 # Service 的端口,内部互相访问的端口
targetPort: webui # 转发到 Pod 的端口,容器内的实际端口
nodePort: 30090 # 节点暴露的端口,外部访问(仅 NodePort 类型需要)
- 集群内部 :通过
svc-filebeat:5601访问。 - 集群外部 :通过
http://<任意节点IP>:30090访问。
NodePort和HostPort对比
- NodePort:所有k8s节点都可以访问。
- HostPort:只能被调度的节点访问。
- 所以NodePort有高可用性。
服务发现的体现
服务发现(Service Discovery)
作用:为Kubernetes Service提供端口映射依据。Service通过targetPort匹配Pod的containerPort,将流量转发到容器。
示例:
yaml
# Pod 定义
containers:
- ports:
- containerPort: 8080
name: app-port
# Service 定义
spec:
ports:
- port: 80 # Service 对外端口
targetPort: app-port # 转发到 Pod 的 8080 端口(通过名称匹配)
命令行操作
bash
# 查看所有service
kubectl get svc -o wide
# 查看service详细信息
kubectl describe svc svc-filebeat
# 进入容器
kubectl exec -it oldboyedu-filebeat -- bash
拓展:服务为什么要使用Service
1. Pod的动态性导致IP不稳定
- Pod是临时资源,生命周期可能因重启、扩缩容、节点故障等原因变化,其Cluster IP会动态改变。
- 直接访问Pod IP的问题:一旦Pod重建,IP变化,依赖方(如其他Pod)会访问失败。
- Service的价值:提供固定的访问入口(Service名称/Cluster IP),自动关联后端Pod(通过标签选择器),屏蔽Pod IP变化的影响。
2. 实现负载均衡和流量分发
- 多个Pod副本(如Deployment管理的Pod)提供同一服务时,Service会自动将流量负载均衡到所有健康Pod。
- 例如:3个Nginx Pod副本,Service通过轮询或会话亲和性分发请求,避免单Pod负载过高。
3. 简化集群内服务发现
- K8s集成DNS服务 (CoreDNS),其他Pod可通过Service名称访问服务(如
http://svc-nginx:80),无需硬编码IP/端口。
4. 支持外部访问(NodePort/Ingress依赖)
- 外部访问集群内服务时,需通过Service作为桥梁(如NodePort暴露节点端口、Ingress绑定Service)。