欢迎光临散文网 会员登陆 & 注册

学习日志 211220 前情提要 配置 有状态服务1

2021-12-20 17:34 作者:mayoiwill  | 我要投稿

# K8s win10下minikube环境搭建 总结

- 安装hyper-v

- 安装minikube

  - 指定hyper-v

  - 指定新增的外部网络虚拟交换机

- 安装docker客户端

- 在K8s上安装私有docker仓库

  - 生成证书

  - 共享目录

- 开发示例Java应用 并部署到K8s上

  - Docker化

  - K8s描述文件


## 思路

- 因为要用微服务 所以要用K8s

- 因为要学K8s 所以要在windows上搭建学习环境

- 所以需要minikube

- 所以需要Hyper-v

- 因为K8s遵守docker image标准

- 所以java 应用需要docker化

- 所以需要Docker仓库

- 因为不想用商用仓库, 所以自己搭一个Docker仓库


# Hyper-V

- 安装 不再重复


# minikube安装

- 环境变量 MINIKUBE_HOME

- 在Hyper-V上建 虚拟交换机, 选外部网络, 命名为minikube

  - 名字可以自取, 下面指令中自己替换掉

- minikube start

  - `minikube start --vm-driver hyperv --hyperv-virtual-switch "minikube"`

  - 指定使用hyperv

  - 指定使用指定的虚拟交换机

- 后续不要再使用minikube start指令

  - 使用hyper-v的保存和启动 指令来启停环境

- 确认minikube虚拟机的IP, 应该形如 192.168.x.x

  - 记下这个IP, 后续称之为 minikube_ip


## Q&A

- Q: 为什么要指定hyper-v

- A: 在装了docker客户端后, 不指定的话默认是用docker的, 但我实际用下来发现docker的不好用

- Q: 为什么要指定使用新增的虚拟交换机(外部IP)

- A: 因为这样比较容易固定下minikube的IP 以便我们后续做docker私有仓库等服务

  - 类似的服务可能需要使用私有证书, 而私有证书是发给IP的, 如果IP总是变, 则私有证书也要变来变去


# 安装docker客户端

- 略


# 在K8s上安装私有docker仓库

- 登录minikube虚拟机 生成证书

  - ssh docker@minikube_ip

  - 默认密码 tcuser

- 参考 https://www.linuxtechi.com/setup-private-docker-registry-kubernetes/

- 生成证书

- 部署 private register pods和services

- 修改windows机(开发机)的/etc/hosts解析 让 k8s-master域名解析到 192.168.2.15

- 测试开发机访问私有仓库

  - 开启开发机的docker客户端

  - 把Java工程的镜像上传到新建的私有仓库

  - docker push k8s-master:31320/springbootdemo:1.0.0

  - 参考Java工程Docker化一项

- 配置 K8s control plane 访问私有仓库

  - ssh minikube_ip

  - 修改 /etc/hosts 如 开发机

  - 复制证书

  - `sudo cp /opt/certs/registry.crt /etc/docker/certs.d/k8s-master:31320/ca.crt`

  - 如果目录不存在就先建目录

- 测试K8s control plane 访问私有仓库

  - ssh minikube_ip

  - docker pull k8s-master:31320/springbootdemo:1.0.0


# 开发Java应用并部署到K8s

- 开发Java spring boot应用

  - 引入web 开8080端口

  - 根路径做个Rest RequestMApping

- Docker化

  - 编写Dockerfile

  - 引入mvn docker plugin(可选) 执行mvn dockerfile:build

  - 重新tag 改仓库 tag

- 部署到K8s上

  - 编写K8s.yaml描述文件

  - 描述deployment

  - 描述service

  - Apply -f


# 总结完毕


# 继续学习 K8s configuration

- 不看k8s的官方文档了 理由是其使用的 import javax.inject.Inject; 技术较旧

- 关键词 k8s springboot configuration

- 参考 https://spring.io/guides/topicals/spring-on-kubernetes/

  - (可选) 引入actuator

    - 设置k8s.yaml healthy check 指向 actuator的healthy

      ```

        livenessProbe:

          httpGet:

            path: /actuator/health/liveness

            port: 8080

        readinessProbe:

          httpGet:

            path: /actuator/health/readiness

            port: 8080

        lifecycle:

          preStop:

            exec:

              command: ["sh", "-c", "sleep 10"]

      ```

  - 重点 Using ConfigMaps To Externalize Configuration


## 在k8s上创建configmap

- 创建一个properties文件

  - 例如 ./k8s/Application.properties

  - 里面写一个springboot相关的配置项 比如

    ```

    server.shutdown=graceful

    management.endpoints.web.exposure.include=*

    ```

  - 使用如下命令创建k8s configmap

    - `kubectl create configmap gs-spring-boot-k8s --from-file=./k8s/Application.properties`

  - 校验

    - `kubectl get configmap gs-spring-boot-k8s -o yaml`

- The last step is to mount this ConfigMap as a volume in the container

  - 把上述configmap做成一个容器上的文件路径

  - 关键代码

    ```

    在containers.readnessProbe同级,加

    volumeMounts:

      - name: config-volume

        mountPath: /App/config

    在containers: 同级 加

    volumes:

      - name: config-volume

        configMap:

          name: gs-spring-boot-k8s

    ```

  - 代码解析

    - 给container指示, 要求其新开一个volumeMounts

      - 源 用名字指定  config-volume

      - 目标 路径给 /App/config

      - 这里是 /App , 不是示例中的/workspace

      - 因为我们的Dockerfile的WORKDIR是/App

    - 创建名叫config-volume的volume

      - 命名 和上述volumeMounts要对应

      - 源 指定为 configMap

      - 名字就是之前创建的configMap的名字 即

      - gs-spring-boot-k8s

- 总结

  - configMap在k8s里是一种资源

  - 可以通过properties的格式创建

  - 可以mount给container的一个目录

  - 这个目录下会有一个叫做Applications.properties的文件

    - 这个文件名是默认的

  - 通过springboot的actuator去读取展示


# 后续关于 Service Discovery and Load Balancing

- 只读 不操作了

- 关键点

  > Kubernetes sets up DNS entries so that we can use the service ID (e.g. name-service) to make an HTTP request to the service without knowing the IP address of the pods. The Kubernetes service also load balances these requests between all the pods.


# k8s教程 configuring redis

- 读一遍 不操作了

- 需要注意的就是 修改了configMap后 需要重建pod使其生效

  - 文档中采取的重建pod的方法是

  - kubectl delete pod redis

  - 之后重新Apply k8s描述文件

- 其它需要注意的点

  - k8s描述文件可以是从网上下载下来的 即使用url

  - configMap的data可以直接写, 不一定要from file

  - configMap可以映射成任何文件名 不一定是Applications.properties

  - 比如例子中被映射为了redis.conf


# Pos Security Admission(PSA)

- 是关于 pod能用什么版本的镜像?

- 在PSA设置比较严格的情况下, deployment不能使用latest的tag的镜像?

- 暂时用不到, 存疑

- 其它需要注意的点

  - 使用kind可以创建新集群

  - 创建集群时 需要指定一个集群image 如 kindest/node:v1.23.0

  - 可以让kubectl匹配给新集群

  - 部分label的key有控制意义, 不能乱打

  - 比如 pod-security.kubernetes.io/enforce


## Apply Pod Security Standards at the Namespace Level

- 其它需要注意的点

  - 使用kubectl create ns xxx 来创建namespace

- 关于namespace的部分以后再说了


# Stateless Applications 无状态应用

- 只读 不操作

- 重点 创建服务时 指定 type=LoadBalancer

  ```

  kubectl expose deployment hello-world --type=LoadBalancer --name=my-service

  ```

  - 感觉之前有服务负载沾着 原因就是service 的 type没有设成LoadBalancer?

  - 这个依赖external load balancer

  - 参考 https://kubernetes.io/docs/tasks/access-Application-cluster/create-external-load-balancer/

  - K8s会负责和外部的load balancer通讯, 汇报内部ip变更之类的

  - 当外部load balancer提供好IP地址后, k8s会记录下来

    - 如果没有外部load balancer 则外部ip这里一直是pending

  - 所以正常情况下, 对外提供的服务不使用和control plane一样的ip(minikube_ip)

  - 而是有自己的ip

- 其它关注的点

  - google云或amazon云 付费后提供kubectl可以使用的API

  - 如何让kubectl和对应的线上租用的云匹配, 要根据对应的云提供商来设置

    - 估计就是下载个证书的事情


# Stateful Applications 有状态应用

- 目标 建个mysql的数据库

- 后续目标 Flink和ElasticSearch


## 前置任务

- HeadlessServices

  - 不需要load-balancing的服务

  - 没有cluster IP

  - headless服务可以结合其它服务发现框架 不用k8s自己的服务发现实现

  - 参考 https://kubernetes.io/docs/concepts/services-networking/service/#headless-services

  - NodePort类型 关键就是在control plane上分配一个port, 路由给内部的服务

  - LoadBalancer类型 就是和外部load balancer协作, 申请一个独立的IP, 再路由给内部的服务

- PersistentVolumes

  - Pods consume node resources and PVCs consume PV resources

- PersistentVolume Provisioning


## 创建一个StatefulSet

- 创建stateful set 替换(相当于)创建deployment

  - 创建 见示例 k8s/web.yaml

  - 检查 `kubectl get statefulset web`

- stateful set里每个pod的创建是顺序的 0创建好了再开始创建1

- stateful set里每个pod有独立固定的id

  - 格式是 <statefulset名字>-<序号>

  - 这个也是每个节点的hostname

  - 用exec试一下

  - 内部DNS也生效了, 内部其它pod可以用nslookup找到web-0.nginx

  - 注意域名格式 web-0.nginx


# 检查固定存储的部分

- 检查pvc

  - `kubectl get pvc -l App=nginx`

  - 此例使用是的动态pvc 自动创建了两个pvc, 绑定到两个pv上

- 上述两个nginx服务各有1G的存储, 不共享

  - 这个是有问题的, 应该搞成共享?

- 重新生成pod不影响存储 pv还在那里

- 后续 TODO Scaling a StatefulSet


# 总结

- StatefulSet

  - 固定DNS记录 针对每一个pod

    - 相对, Stateless则是多个pod共享一个service的DNS解析记录

  - 固定的存储

    - 就算删除pod重新创建, 存储还是在的

    - 相对, Stateless则一般没有存储, 就算有日志什么的, 重新创建pod的话应该也丢失了


学习日志 211220 前情提要 配置 有状态服务1的评论 (共 条)

分享到微博请遵守国家法律