k8s构建容器化微服务项目

容器化微服务项目

熟悉Spring Cloud微服务项目

1639991817856.png

源代码编译构建

#安装jdk、maven
[root@prometheus simple-microservice-dev3]# yum install java-1.8.0-openjdk maven

#修改product、stock、order连接数据库地址
url: jdbc:mysql://192.168.153.27:3306/tb_order?characterEncoding=utf-8
url: jdbc:mysql://192.168.153.27:3306/tb_product?characterEncoding=utf-8
url: jdbc:mysql://192.168.153.27:3306/tb_stock?characterEncoding=utf-8

#编译构建
[root@prometheus simple-microservice-dev3]# mvn clean package -Dmaven.test.skip=true

构建项目镜像并推送到镜像仓库

登录harbor

[root@prometheus harbor]# docker login 192.168.153.20

eureka

[root@prometheus eureka-service]# docker build -t 192.168.153.20/ms/eureka:v1 .
[root@prometheus eureka-service]# docker push 192.168.153.20/ms/eureka:v1

K8s中部署Eureka集群

安装Ingress

[root@k8s-m1 k8s]# kubectl apply -f ingress-controller.yaml 
[root@k8s-m1 k8s]#  kubectl get pods -n ingress-nginx -o wide
NAME                                       READY   STATUS   IP               NODE     
nginx-ingress-controller-5dc64b58f-stb5j   1/1     Running  192.168.153.25   k8s-m1   

创建registry-pull-secret

[root@k8s-m1 k8s]# kubectl create secret docker-registry registry-pull-secret --docker-username=admin --docker-password=Harbor12345 --docker-server=192.168.153.20 
secret/registry-pull-secret created

部署eureka集群

[root@k8s-m1 k8s]# kubectl apply -f eureka.yaml 
[root@k8s-m1 k8s]# kubectl get pod,svc -n ms
NAME           READY   STATUS    RESTARTS   AGE
pod/eureka-0   1/1     Running   0          6m55s
pod/eureka-1   1/1     Running   0          2m43s
pod/eureka-2   1/1     Running   0          95s

NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/eureka   ClusterIP   None         <none>        8888/TCP   6m55s
---------------------------------------------------------------------------------
hosts:
192.168.153.27 eureka.ctnrs.com
#访问:
http://eureka.ctnrs.com/

K8s中部署MySQL

部署mysql

#拉起MySQL镜像(:5.7 表示5.7版本)
docker pull mysql:5.7
#运行MySQL容器
docker run -d -p 3306:3306 --privileged=true -v /docker/mysql/conf/my.cnf:/etc/my.cnf -v /docker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
#参数说明:
run run 是运行一个容器
-d  表示后台运行
-p  表示容器内部端口和服务器端口映射关联
--privileged=true 设值MySQL 的root用户权限, 否则外部不能使用root用户登陆
-v /docker/mysql/conf/my.cnf:/etc/my.cnf 将服务器中的my.cnf配置映射到docker中的/docker/mysql/conf/my.cnf配置
-v /docker/mysql/data:/var/lib/mysql  同上,映射数据库的数据目录, 避免以后docker删除重新运行MySQL容器时数据丢失
-e MYSQL_ROOT_PASSWORD=123456   设置MySQL数据库root用户的密码
--name mysql     设值容器名称为mysql
mysql:5.7  表示从docker镜像mysql:5.7中启动一个容器
--character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci 设值数据库默认编码


#赋予远程登录权限
[root@xdclass ~]# docker exec -it mysql bash  
root@ce7e026432b3:/# mysql -u root -p

mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql>  FLUSH PRIVILEGES;

#导入数据
 order.sql  stock.sql  product.sql

在K8s中部署微服务

product

#构建镜像
[root@prometheus product-service-biz]#  docker build -t 192.168.153.20/ms/product:v1 .
#推送镜像
[root@prometheus product-service-biz]#  docker push 192.168.153.20/ms/product:v1
#k8s集群中发布
[root@k8s-m1 k8s]# kubectl apply -f product.yaml 

order

#构建镜像
[root@prometheus order-service-biz]# docker build -t 192.168.153.20/ms/order:v1 .
#推送镜像
[root@prometheus order-service-biz]# docker push 192.168.153.20/ms/order:v1
#k8s集群中发布
[root@k8s-m1 k8s]# kubectl apply -f order.yaml 

stock

#构建镜像
[root@prometheus stock-service-biz]# docker build -t 192.168.153.20/ms/stock:v1 .
#推送镜像
[root@prometheus stock-service-biz]# docker push 192.168.153.20/ms/stock:v1
#k8s集群中发布
[root@k8s-m1 k8s]# kubectl apply -f stock.yaml 

gateway

#构建镜像
[root@prometheus gateway-service]# docker build -t 192.168.153.20/ms/gateway:v1 .
#推送镜像
[root@prometheus gateway-service]# docker push 192.168.153.20/ms/gateway:v1
#k8s集群中发布
[root@k8s-m1 k8s]# kubectl apply -f gateway.yaml 
#hosts
192.168.153.27 gateway.ctnrs.com

portal

#构建镜像
[root@prometheus portal-service]# docker build -t 192.168.153.20/ms/portal:v1 .
#推送镜像
[root@prometheus portal-service]# docker push 192.168.153.20/ms/portal:v1
#k8s集群中发布

portal.ctnrs.com

查看相关服务

[root@k8s-m1 k8s]# kubectl get pod,svc,ing -n ms
NAME                           READY   STATUS    RESTARTS   AGE
pod/eureka-0                   1/1     Running   2          86m
pod/eureka-1                   1/1     Running   2          84m
pod/eureka-2                   1/1     Running   1          83m
pod/gateway-6c7b6f7c85-g9srj   1/1     Running   1          70m
pod/order-65b848c67c-r7stp     1/1     Running   0          6m58s
pod/portal-78ccc5768c-wvt5f    1/1     Running   1          70m
pod/product-59c88fbf7f-snrkf   1/1     Running   0          7m4s
pod/stock-c9b89d8b-p4wvd       1/1     Running   0          6m51s

NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/eureka    ClusterIP   None         <none>        8888/TCP   86m
service/gateway   ClusterIP   10.0.0.101   <none>        9999/TCP   70m
service/portal    ClusterIP   10.0.0.44    <none>        8080/TCP   70m

NAME                                CLASS    HOSTS               ADDRESS   PORTS   AGE
ingress.networking.k8s.io/eureka    <none>   eureka.ctnrs.com              80      86m
ingress.networking.k8s.io/gateway   <none>   gateway.ctnrs.com             80      70m
ingress.networking.k8s.io/portal    <none>   portal.ctnrs.com              80      70m
1640014289523.png
1640058334935.png
1640058349907.png
http://gateway.ctnrs.com/product/queryAllProduct?page=1&limit=10

{"status":200,"msg":"success","result":[{"id":1,"productName":"测试商品1","price":99.99,"stock":99},{"id":2,"productName":"美女","price":999.0,"stock":87},{"id":3,"productName":"Q币","price":100.0,"stock":77},{"id":4,"productName":"貂皮大衣很厚很厚的那种","price":9999.0,"stock":66}]}

http://gateway.ctnrs.com/order/queryAllOrder
{"status":200,"msg":"success","result":[{"id":1,"orderNumber":"0j889r86wo0tng9x","orderProductName":"美女","orderPrice":999.0,"count":1,"buyDate":"2021-12-21T03:40:32.000+0000"}]}

Skywalking

介绍

• 多种监控手段。可以通过语言探针和 service mesh 获得监控是数据。
• 多个语言自动探针。包括 Java,.NET Core 和 Node.JS。
• 轻量高效。无需大数据平台,和大量的服务器资源。
• 模块化。UI、存储、集群管理都有多种机制可选。
• 支持告警。
• 优秀的可视化解决方案

架构

1640089757346.png

部署

部署ES数据库

docker run --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" -d elasticsearch:7.7.0

部署Skywalking OAP

[root@k8s-m1 ~]# yum install java-11-openjdk –y
[root@k8s-m1 ~]# tar zxvf apache-skywalking-apm-es7-8.3.0.tar.gz
[root@k8s-m1 ~]# cd apache-skywalking-apm-bin-es7/
[root@k8s-m1 ~]# vi config/application.yml
storage:
selector: ${SW_STORAGE:elasticsearch7} #这里使用elasticsearch7
...
elasticsearch7:
nameSpace: ${SW_NAMESPACE:""}
clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:192.168.0.10:9200} # 指定ES地址

#启动OAP和UI:
[root@k8s-m1 bin]# ./startup.sh 
SkyWalking OAP started successfully!
SkyWalking Web Application started successfully!
#访问UI:
http://192.168.153.25:8080


#collector.backend_service为Skywalking服务器,11800端口复制收集数据
[root@k8s-m1 agent]# ss -antp|grep 11800
LISTEN     0      128         :::11800                   :::*                   users:(("java",pid=59156,fd=269))

1640092815351.png

Dockerfile

#启动Java程序以探针方式集成Agent(以eureka为例),每个服务都要加,重新构建:

java -jar -javaagent:/skywalking/skywalking-agent.jar=agent.service_name=ms-eureka,agent.instance_name=$(echo $HOSTNAME | awk -F- '{print $1"-"$NF}'),
collector.backend_service=192.168.153.25:11800 -Deureka.instance.hostname=${MY_POD_NAME}.eureka.ms /eureka-service.jar    


构建发布

#启动mysql服务
docker start mysql

#启动es
docker start elasticsearch

#启动Skywalking OAP和UI:
[root@k8s-m1 bin]# ./startup.sh 
SkyWalking OAP started successfully!
SkyWalking Web Application started successfully!
#访问UI:
http://192.168.153.25:8080


#collector.backend_service为Skywalking服务器,11800端口复制收集数据
[root@k8s-m1 agent]# ss -antp|grep 11800
LISTEN     0      128         :::11800                   :::*                   users:(("java",pid=59156,fd=269))

#修改Dockerfile重新构建推送
docker build -t 192.168.153.20/ms/eureka:v2 .
docker push 192.168.153.20/ms/eureka:v2
......

#k8s发布过程中出现oomkill问题
解决:将limit设置的更大

[root@k8s-m1 k8s]# kubectl get pod,svc,ing -n ms
NAME                           READY   STATUS    RESTARTS   AGE
pod/eureka-0                   1/1     Running   0          62m
pod/eureka-1                   1/1     Running   0          61m
pod/eureka-2                   1/1     Running   0          60m
pod/gateway-77776889-r29dt     1/1     Running   0          34m
pod/order-846f7c95b9-dpqh8     1/1     Running   0          30m
pod/portal-66cf475fc4-9ww57    1/1     Running   1          49m
pod/product-554d7d554c-6g87b   1/1     Running   0          30m
pod/stock-546b455df8-nblxn     1/1     Running   0          30m

NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/eureka    ClusterIP   None         <none>        8888/TCP   62m
service/gateway   ClusterIP   10.0.0.173   <none>        9999/TCP   34m
service/portal    ClusterIP   10.0.0.94    <none>        8080/TCP   49m

NAME                                CLASS    HOSTS               ADDRESS   PORTS   AGE
ingress.networking.k8s.io/eureka    <none>   eureka.ctnrs.com              80      62m
ingress.networking.k8s.io/gateway   <none>   gateway.ctnrs.com             80      34m
ingress.networking.k8s.io/portal    <none>   portal.ctnrs.com              80      49m

效果展示

1640175090524.png
1640176967598.png

生产环境踩坑经验分享

限制了容器资源,还经常被杀死?

在JAVA1.9版本之前,是不能自动发现docker设置的内存限制,随着应用负载起伏就会造成内存使用过大,超过limits限制,从而触发K8s杀掉该容器。

解决办法:
• 手动指定JVM堆内存大小

CMD java -jar $JAVA_OPTS /gateway-service.jar
env:
  - name: JAVA_OPTS
    value: "-Xmx1g"
resources:
  requests:
    cpu: 0.5
    memory: 256Mi
  limits:
    cpu: 1
    memory: 1Gi

滚动更新期间造成流量丢失

滚动更新触发,Pod在删除过程中,有些节点kube-proxy还没来得及同步iptables规则,从而部分流量请求到Terminating的Pod上,导致请求出错。
解决办法:配置preStop回调,在容器终止前优雅暂停5秒,给kube-proxy多预留一点时间

lifecycle:
  preStop:
    exec:
      command:
      - sh
      - -c
      - "sleep 5"
      
还可以做一些回调处理,curl......      

滚动更新之健康检查重要性

滚动更新是默认发布策略,当配置健康检查时,滚动更新会根据Probe状态来决定是否继续更新以及是否允许接入流量,这样在整个滚动更新过程中可保证始终会有可用的Pod存在,达到平滑升级
readinessProbe:
  tcpSocket:
    port: 9999
  initialDelaySeconds: 60
  periodSeconds: 10
livenessProbe:
  tcpSocket:
    port: 9999
  initialDelaySeconds: 60
  periodSeconds: 10
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容