k8s 部署 ruoyi 前后端分离项目

本文视频版

https://www.bilibili.com/video/BV17ugkePEeN

参考

https://blog.csdn.net/qq_50247813/article/details/136934090
https://gitee.com/nasaa/RuoYi-Vue-cloud
https://www.itsgeekhead.com/tuts/kubernetes-129-ubuntu-22-04-3/
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
https://github.com/Joxit/docker-registry-ui/issues/140

前置条件

三台虚拟机:

hostnameip作用
node80192.168.10.80k8s 节点,控制平面
node81192.168.10.81k8s 节点
node82192.168.10.82k8s 节点
node84192.168.10.84镜像仓库

三台虚拟机都配置了主机名和 ip 的映射,windows 也配置了主机名到 ip 的映射。
三台虚拟机都能访问互联网,最好能访问国外仓库。

安装 k8s

确保 k8s 在启动时加载内核模块 overlaybr_netfilter两个内核模块:

printf "overlay\nbr_netfilter\n" >> /etc/modules-load.d/containerd.conf

立即加载 overlaybr_netfilter 内核模块:

modprobe overlay
modprobe br_netfilter

配置 k8s 的网络:

printf "net.bridge.bridge-nf-call-iptables = 1\nnet.ipv4.ip_forward = 1\nnet.bridge.bridge-nf-call-ip6tables = 1\n" >> /etc/sysctl.d/99-kubernetes-cri.conf

image.png
重新加载配置:

sysctl --system

image.png
安装 containerd:

wget https://github.com/containerd/containerd/releases/download/v1.7.13/containerd-1.7.13-linux-amd64.tar.gz -P /opt/software/
tar Cxzvf /usr/local /opt/software/containerd-1.7.13-linux-amd64.tar.gz
wget https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -P /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now containerd

安装 runc:

wget https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64 -P /opt/software/
install -m 755 /opt/software/runc.amd64 /usr/local/sbin/runc

image.png
安装 cni 网络插件:

wget https://github.com/containernetworking/plugins/releases/download/v1.4.0/cni-plugins-linux-amd64-v1.4.0.tgz -P /opt/software/
mkdir -p /opt/cni/bin
tar Cxzvf /opt/cni/bin /opt/software/cni-plugins-linux-amd64-v1.4.0.tgz

修改 containerd 的配置并重启 containerd:

mkdir -p /etc/containerd
containerd config default | tee /etc/containerd/config.toml
vim /etc/containerd/config.toml
# 修改 SystemdCgroup 配置项的值为 true

systemctl restart containerd

关闭 swap:

vim /etc/fstab

注释掉最后一行:
image.png
更新 apt-get 并信任 k8s 官网链接:

apt-get update
apt-get install -y apt-transport-https ca-certificates curl gpg

mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

apt-get update

重启:

reboot

下载 k8s 软件包:

apt-get install -y kubelet=1.29.1-1.1 kubeadm=1.29.1-1.1 kubectl=1.29.1-1.1
apt-mark hold kubelet kubeadm kubectl

apt-mark hold kubelet kubeadm kubectl 命令的作用是将 kubeletkubeadmkubectl 这三个软件包标记为“保留”状态。这意味着这些软件包不会被系统自动升级或删除

检查 swap 是否关闭,确保 swap 是 0:

free -m

下面这些步骤仅仅需要在控制平面节点执行:

# 这个命令会比较耗时
kubeadm init --pod-network-cidr 10.10.0.0/16 --kubernetes-version 1.29.1 --node-name node80

export KUBECONFIG=/etc/kubernetes/admin.conf

# add Calico 3.27.2 CNI 
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/tigera-operator.yaml
wget https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/custom-resources.yaml
# 将 CIDR 配置为 10.10.0.0/16
vim custom-resources.yaml
kubectl apply -f custom-resources.yaml

# 获取 worker 节点加入到集群的命令
kubeadm token create --print-join-command

image.png

在 worker 节点执行上面获取到的将 worker 节点加入到集群的命令将当前节点加入到 k8s 集群中:

kubeadm join 192.168.10.80:6443 --token pecvqm.rlxcsywbvm2resvv \
        --discovery-token-ca-cert-hash sha256:fac6cb7a265dc30d7560517dc64debaf933592215a58a8912453f6a56bde7701

–pod-network-cidr 明确了 Kubernetes 集群中 Pod 网络的 IP 地址范围

安装镜像仓库 registry

安装 htpasswd 工具:

sudo apt-get update
sudo apt-get install apache2-utils

创建挂载容器的目录以及密码文件:

mkdir -p /docker/volume/registry/auth/
htpasswd -Bc /docker/volume/registry/auth/htpasswd root
# 输入 root 的密码

创建 registry 容器挂载数据的目录:

mkdir -p /docker/volume/registry/data

创建 registry 挂载配置文件的目录,并创建配置文件:

mkdir -p /docker/volume/registry/conf
vim /docker/volume/registry/conf/config.yml
version: 0.1
log:
  level: debug
  fields:
    service: registry
    environment: production
storage:
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
  headers:
    Access-Control-Allow-Origin: ['http://node84:8080','http://192.168.10.84']
    Access-Control-Allow-Methods: ['HEAD', GET', 'OPTIONS', 'DELETE', 'POST', 'PUT']
    Access-Control-Allow-Headers: ['Authorization','Accept']
  http2:
    disabled: false
auth:
  htpasswd:
    realm: basic-realm
    path: /auth/htpasswd

创建 docker 网络:

docker network create registry-net

启动 registry 容器:

docker run -d \
  --name registry \
  --network registry-net \
  -v /docker/volume/registry/auth:/auth \
  -v /docker/volume/registry/data:/var/lib/registry \
  -v /docker/volume/registry/conf/config.yml:/etc/docker/registry/config.yml \
  -e REGISTRY_AUTH=htpasswd \
  -e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  -e REGISTRY_HTTP_SECRET=secretkey \
  -p 5000:5000 \
  registry:2

修改 containerd 的配置,将 registry 的地址添加到镜像仓库列表中:

mkdir -p /etc/containerd/certs.d/node84:5000

tee /etc/containerd/certs.d/node84:5000/hosts.toml << 'EOF'
server = "http://node84:5000"

[host."http://node84:5000"]
  capabilities = ["pull", "resolve", "push"]
  skip_verify = true
EOF

systemctl restart containerd.service

因为我们需要将 docker 上的镜像推送到 registry 中,所以,也需要修改 docker 的配置,添加我们的 registry 镜像仓库的地址。
将 node84 添加到 docker 的安全镜像仓库名单中,避免使用 docker 推送镜像到 registry 中报错,将 “insecure-registries”: [“192.168.56.10:5000”]’ 加入到 /etc/docker/daemon.json 中,再使用 systemctl restart docker 重启 Docker 就可以了。

{
    "insecure-registries": ["node84:5000"]
}

安装 registry 可视化工具

启动一个 registry-browser 容器并连接到自定义网络:

docker run -d \
  --name registry-browser \
  --network registry-net \
  -e REGISTRY_TITLE="Docker Registry Browser" \
  -e NGINX_PROXY_PASS_URL="http://registry:5000" \
  -e REGISTRY_AUTH="true" \
  -e REGISTRY_AUTH_USER="root" \
  -e REGISTRY_AUTH_PASSWORD="123456" \
  -p 8080:80 \
  joxit/docker-registry-ui:latest

比较老的版本中使用 -e REGISTRY_URL=“http://registry:5000” \ 配置 registry 的地址,如果新版本中使用这个配置,在前端会出现 An error occured: Check your connection and your registry must have Access-Control-Allow-Origin header set to http://node84:8080这个异常,需要使用 NGINX_PROXY_PASS_URL 这个配置

访问主机的 8080 端口即可看到 registry 中的镜像。

部署 ruoyi 前后端分离项目

制作后端镜像

编写 Dockerfile 文件:

# 使用官方的 OpenJDK 8 镜像作为基础镜像
FROM openjdk:8-jdk-alpine
# 创建存放上传文件的目录
RUN mkdir -p /opt/project/ruoyi/ruoyi-backend/upload-file-path
# 创建存放日志的目录
RUN mkdir -p /opt/project/ruoyi/ruoyi-backend/logs
# 安装字体文件
RUN mkdir -p /etc/apk/
RUN touch /etc/apk/repositories
RUN echo -e 'https://mirrors.aliyun.com/alpine/v3.6/main/\nhttps://mirrors.aliyun.com/alpine/v3.6/community/' > /etc/apk/repositories
RUN set -xe && apk --no-cache add ttf-dejavu fontconfig
# 设置工作目录
WORKDIR /opt/project/ruoyi/ruoyi-backend
# 将构建好的 JAR 文件复制到容器中
COPY ./ruoyi-admin/target/ruoyi-admin.jar ruoyi-admin.jar
# 暴露应用程序端口
EXPOSE 8080
# 启动应用程序
CMD ["nohup","java","-jar","/opt/project/ruoyi/ruoyi-backend/ruoyi-admin.jar", ">", "/opt/project/ruoyi/ruoyi-backend/logs/nohup.log", "&"]

直接用 idea 连接到我们虚拟机中的 Docker 上,在 idea 中点击 Dockerfile 中的绿色箭头将后端打成镜像。
在虚拟机中查看镜像是否好了:

docker images

将打好的后端镜像推送到 registry 中:

#推送后端镜像
#修改镜像tag
docker tag ruoyi-backend:1.0 node84:5000/ruoyi-backend:1.0

# 因为 registry 设置了用户名和密码,所以需要先登录才能推送镜像
docker login -u root -p 123456 node84:5000

#推送到私有镜像仓库中
docker push node84:5000/ruoyi-backend:1.0

制作前端镜像

编写前端的 Dockerfile:

# 使用 Nginx 作为基础镜像
FROM nginx:1.12.2
# 将 nginx.conf 拷贝到容器中
COPY nginx.conf /etc/nginx/nginx.conf
# 创建存放前端编译后代码的目录
RUN mkdir -p /opt/project/ruoyi/ruoyi-front-code
# 将构建好的应用拷贝到 Nginx 的默认 web 目录
COPY dist /opt/project/ruoyi/ruoyi-front-code
# Expose 端口
EXPOSE 80
# 启动 Nginx 服务器
CMD ["nginx", "-g", "daemon off;"]

直接用 webstorm 连接到我们虚拟机中的 Docker 上,在 webstorm 中点击 Dockerfile 中的绿色箭头将后端打成镜像。
在虚拟机中查看镜像是否好了:

docker images

将打好的前端镜像推送到 registry 中:

#推送前端镜像
#修改镜像tag
docker tag ruoyi-frontend:1.0 node84:5000/ruoyi-frontend:1.0

# 因为 registry 设置了用户名和密码,所以需要先登录才能推送镜像
docker login -u root -p 123456 node84:5000

#推送到私有镜像仓库中
docker push node84:5000/ruoyi-frontend:1.0

k8s 部署后端

将后端初始化的两个 sql 文件创建为 configmap

将 ruoyi 后端的两个初始化 sql 文件放入 /opt/ruoyi/sql 中:

mkdir -p /opt/ruoyi/sql

切换成 k8s 的管理员:

export KUBECONFIG=/etc/kubernetes/admin.conf

这种切换方式重启后会失效,可以向 ~/.bashrc 文件末尾添加 export KUBECONFIG=/etc/kubernetes/admin.conf 后,再使用 source ~/.bashrc 使配置永久生效

使用如下命令检查是否切换成功:

kubectl cluster-info

创建一个为我们当前机器分配在 default 空间下创建 configmap 权限的配置文件:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: configmap-creator
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["create", "update", "patch", "delete"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: configmap-creator-binding
  namespace: default
subjects:
- kind: User
  name: system:node:node80
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: configmap-creator
  apiGroup: rbac.authorization.k8s.io

使这个配置文件生效:

kubectl apply -f role-config.yaml

当前节点就有在 default 空间下创建 configmap 的权限了。
根据 ruoyi 后端的初始化 SQL 文件创建 configMap:

注意:sql 文件头部要加上:use ry-vue; SET NAMES utf8;

kubectl create configmap ruoyi-init-sql-config-map --from-file=/opt/ruoyi/sql
# 查看这个 configmap 的详情
kubectl describe configmap/ruoyi-init-sql-config-map

将需要修改的后端配置创建为 configmap

后端的镜像中,application.yaml 配置文件中 MySQL 和 Redis 的地址都是写死的,需要我们根据要求创建在 k8s 中使用的 configMap。
拷贝一份 application.yaml 配置文件,将其中的 ip 地址改为对应 service 的服务名地址:

# 数据源配置
spring:
    redis:
      # 地址
      host: ruoyi-redis-service
      # 端口,默认为6379
      port: 6379
      # 数据库索引
      database: 0
      # 密码
      password: 123456
      # 连接超时时间
      timeout: 10s
      lettuce:
        pool:
          # 连接池中的最小空闲连接
          min-idle: 0
          # 连接池中的最大空闲连接
          max-idle: 8
          # 连接池的最大数据库连接数
          max-active: 8
          # #连接池最大阻塞等待时间(使用负值表示没有限制)
          max-wait: -1ms
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        druid:
            # 主库数据源
            master:
                url: jdbc:mysql://ruoyi-mysql-service:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&connectTimeout=1000&socketTimeout=30000&autoReconnect=true&failOverReadOnly=false
                username: root
                password: 123456
            # 从库数据源
            slave:
                # 从数据源开关/默认关闭
                enabled: false
                url:
                username:
                password:
            # 初始连接数
            initialSize: 5
            # 最小连接池数量
            minIdle: 10
            # 最大连接池数量
            maxActive: 20
            # 配置获取连接等待超时的时间
            maxWait: 60000
            # 配置连接超时时间
            connectTimeout: 30000
            # 配置网络超时时间
            socketTimeout: 60000
            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
            timeBetweenEvictionRunsMillis: 60000
            # 配置一个连接在池中最小生存的时间,单位是毫秒
            minEvictableIdleTimeMillis: 300000
            # 配置一个连接在池中最大生存的时间,单位是毫秒
            maxEvictableIdleTimeMillis: 900000
            # 配置检测连接是否有效
            validationQuery: SELECT 1 FROM DUAL
            testWhileIdle: true
            testOnBorrow: false
            testOnReturn: false
            webStatFilter:
                enabled: true
            statViewServlet:
                enabled: true
                # 设置白名单,不填则允许所有访问
                allow:
                url-pattern: /druid/*
                # 控制台管理用户名和密码
                login-username: ruoyi
                login-password: 123456
            filter:
                stat:
                    enabled: true
                    # 慢SQL记录
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    merge-sql: true
                wall:
                    config:
                        multi-statement-allow: true

根据这个配置文件生成 configMap:

kubectl create configmap ruoyi-admin-config --from-file=/opt/ruoyi/application-k8s.yaml
kubectl describe configmap/ruoyi-admin-config

将 redis 服务的配置 redis.conf 创建为 configmap

下载需要的 redis 对应版本,解压后拷贝 redis.conf 文件,修改配置文件中的如下部分:

# 注释掉 bind 127.0.0.1,bind 用于限制访问 Redis 的机器 ip,直接关掉
# bind 127.0.0.1

# 修改 daemonize no 为 yes,让 Redis 可以后台启动
daemonize yes

# 设置密码
requirepass 123456

根据这个 redis.conf 配置文件生成 configMap:

kubectl create configmap ruoyi-redis-config-map --from-file=/opt/ruoyi/redis.conf
kubectl describe configmap/ruoyi-redis-config-map

将 registry 的用户名和密码创建为 secret

创建一个 secret 用于存储我们的 registry 仓库的用户名和密码,在 k8s 资源编排 yaml 文件中,在 deployment 中使用 imagePullSecrets 字段就可以引用这个 Secret 对象,这样 Kubernetes 就可以在拉取镜像时使用这个 Secret 对象中的认证信息。

kubectl create secret registry-user-pwd-secret \
    --docker-server=http://node84:5000 \
    --docker-username=root \
    --docker-password=123456

containerd 添加 registry 镜像仓库地址

因为我们使用的 registry 是 http 协议,containerd 默认认为是不安全的,需要做如下配置,修改 containerd 的配置,使得 containerd 从 registry 拉取镜像不会报错:
image.png

[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."node84:5000"]
    endpoint = ["http://node84:5000"]

注意:上面的 node84 是 registry 的地址,如果 registry 地址不是 node84,两个 node84 都需要更改为你的 registry 的地址,所有 k8s 机器都需要修改

sudo systemctl restart containerd

部署后端服务

后端部署的 k8s 资源清单:

# 数据库
apiVersion: apps/v1
kind: Deployment
metadata:
  name: database
  namespace: default
spec:
  selector:
    matchLabels:
      app: database
  template:
    metadata:
      labels:
        app: database
    spec:
      containers:
        - name: database
          image: mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "123456"
            - name: MYSQL_DATABASE
              value: "ry-vue"
          volumeMounts:
            - mountPath: /docker-entrypoint-initdb.d
              name: ruoyi-init-sql
          resources:
            limits:
              memory: "512Mi"
              cpu: "500m"
          ports:
            - containerPort: 3306
      volumes:
        - name: ruoyi-init-sql
          configMap:
            name: ruoyi-init-sql-config-map
      imagePullSecrets:
        - name: registry-user-pwd-secret

---
apiVersion: v1
kind: Service
metadata:
  name: ruoyi-mysql-service
  namespace: default
spec:
  selector:
    app: database
  ports:
    - port: 3306
      targetPort: 3306

---
# redis
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:7.2.0
          resources:
            limits:
              memory: "512Mi"
              cpu: "500m"
          ports:
            - containerPort: 6379
          volumeMounts:
            - mountPath: /usr/local/etc/redis/redis.conf
              name: ruoyi-redis-config
      volumes:
        - name: ruoyi-redis-config
          configMap:
            name: ruoyi-redis-config-map
      imagePullSecrets:
        - name: registry-user-pwd-secret

---
apiVersion: v1
kind: Service
metadata:
  name: ruoyi-redis-service
  namespace: default
spec:
  selector:
    app: redis
  ports:
    - port: 6379
      targetPort: 6379

# ruoyi 后端
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ruoyi-java
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ruoyi-java
  template:
    metadata:
      labels:
        app: ruoyi-java
    spec:
      initContainers:
        - name: wait-for-mysql
          image: mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "123456"
          command:
            - sh
            - -c
            - |
              set -e
              maxTries=10
              while [ "$$maxTries" -gt 0 ] \
                    && ! mysqladmin ping --connect-timeout=3 -s \
                                    -hruoyi-mysql-service -uroot -p$$MYSQL_ROOT_PASSWORD
              do 
                  echo 'Waiting for MySQL to be available'
                  sleep 5
                  let maxTries--
              done
              if [ "$$maxTries" -le 0 ]; then
                  echo >&2 'error: unable to contact MySQL after 10 tries'
                  exit 1
              fi
        - name: wait-for-redis
          image: redis:7.2.0
          env:
            - name: REDIS_PASSWORD
              value: "123456"
          command:
            - sh
            - -c
            - |
              set -e
              maxTries=10
              while [ "$$maxTries" -gt 0 ] \
                    && ! timeout 3 redis-cli -h ruoyi-redis-service -a $$REDIS_PASSWORD ping
              do 
                  echo 'Waiting for Redis to be available'
                  sleep 5
                  let maxTries--
              done
              if [ "$$maxTries" -le 0 ]; then
                  echo >&2 'error: unable to contact Redis after 10 tries'
                  exit 1
              fi
      containers:
        - name: ruoyi-java
          image: node84:5000/ruoyi-backend:1.0
          resources:
            limits:
              memory: "512Mi"
              cpu: "512m"
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
          # /app/ruoyi/ 是 dockerfile 中拷贝 jar 包所到的目录
          # springboot 启动时,会从 jar 包所在的目录的 config 子目录中查找配置文件
          volumeMounts:
            - mountPath: /opt/project/ruoyi/ruoyi-backend/config
              name: config
          # 使用 application-k8s.yaml 作为配置文件
          args:
            ["java", "-jar", "ruoyi-admin.jar", "--spring.profiles.active=k8s"]
      volumes:
        - name: config
          configMap:
            name: ruoyi-admin-config
      imagePullSecrets:
        - name: registry-user-pwd-secret
---
apiVersion: v1
kind: Service
metadata:
  name: ruoyi-backend-service
  namespace: default
spec:
  selector:
    app: ruoyi-java
  ports:
    - port: 8080
      targetPort: 8080

根据资源清单部署后端:

kubectl apply -f ruoyi-k8s-backend.yaml

k8s 部署前端

将前端的 nginx.conf 创建为 configmap

Nginx 的配置文件:

server {
  listen       80;
  server_name  localhost;
  charset utf-8;

  location / {
    # dockerfile中WORKDIR目录
    root   /opt/project/ruoyi/ruoyi-front-code;
    try_files $uri $uri/ /index.html;
    index  index.html index.htm;
  }

  location /prod-api/ {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # 后端 service 的 DNS
    proxy_pass http://ruoyi-backend-service.default:8080/;
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root   html;
  }
}

根据 Nginx 配置文件创建 configMap:

kubectl create configmap ruoyi-ui-config --from-file=/opt/ruoyi/nginx.conf
kubectl describe configmap/ruoyi-ui-config

部署前端服务

前端部署的 k8s 资源清单:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ruoyi-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ruoyi-nginx
  template:
    metadata:
      labels:
        app: ruoyi-nginx
    spec:
      initContainers:
        - name: wait-for-ruoyi-backend-service
          image: alpine
          command:
            - sh
            - -c
            - |
              apk add --no-cache curl
              echo "Starting to wait for ruoyi-backend-service..."
              until curl -s -f -m 3 http://ruoyi-backend-service:8080
              do
                echo "Waiting for ruoyi-backend-service...";
                sleep 5;
              done
              echo "ruoyi-backend-service is available now."
      containers:
        - name: ruoyi-nginx
          image: node84:5000/ruoyi-frontend:1.0
          resources:
            limits:
              memory: "512Mi"
              cpu: "512m"
          imagePullPolicy: Always
          ports:
            - containerPort: 80
          volumeMounts:
            - mountPath: /etc/nginx/conf.d
              name: config
      volumes:
        - name: config
          configMap:
            name: ruoyi-ui-config
            items:
              - key: nginx.conf
                path: default.conf
      imagePullSecrets:
        - name: registry-user-pwd-secret

---
apiVersion: v1
kind: Service
metadata:
  name: ruoyi-fronted-service
  namespace: default
spec:
  type: NodePort
  selector:
    app: ruoyi-nginx
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30000

根据资源清单启动前端:

kubectl apply -f ruoyi-k8s-fronted.yaml

前端通过 nodePort 暴露出去了,访问任意 k8s 节点的 30000 端口即可访问前端。

遇到的问题

拉取镜像失败

只要出现这种情况:

ctr: failed to copy: httpReadSeeker: failed open: failed to do request: Get "https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/52/52d2b7f179e32b4cbd579ee3c4958027988f9a8274850ab0c7c24661e3adaac5/data?verify=1719112771-ZRsD38JmAnzgLW0YPDJ4BVoEmvw%3D": dial tcp 162.220.12.226:443: connect: connection refused

就是网络不通,需要开代理。
可以使用如下命令测试拉取镜像是否能成功:

sudo ctr images pull docker.io/library/redis:7.2.0

可以配置 containerd 使用阿里云的镜像仓库加速:

vim /etc/containerd/config.toml
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."node63:5000"]
          endpoint = ["http://node63:5000"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
          endpoint = ["https://6zemac9k.mirror.aliyuncs.com"]

修改后重启 containerd:

sudo systemctl restart containerd

配置完后,拉取镜像的时候并没有从 aliyun 拉取,不知道为什么。
最后我还是选择了使用代理。

拉取前后端镜像失败

containerd 的配置 /etc/containerd/config.toml 中:
[plugins.“io.containerd.grpc.v1.cri”.registry.mirrors]
[plugins.“io.containerd.grpc.v1.cri”.registry.mirrors.“node63:5000”]
endpoint = [“http://node63:5000”]
[plugins.“io.containerd.grpc.v1.cri”.registry.mirrors.“docker.io”]
endpoint = [“https://6zemac9k.mirror.aliyuncs.com”]

registry.mirrors.“node63:5000” 之前因为忘了修改,应该要改成现在的 registry 的地址 node63:5000。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/737227.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kimichat使用案例026:AI翻译英语PDF文档的3种方法

文章目录 一、介绍二、腾讯交互翻译TranSmart https://transmart.qq.com/三、沉浸式翻译三、谷歌网页翻译一、介绍 短的文章,直接丢进kimichat、ChatGPT里面很快就可以翻译完成,而且效果很佳。但是,很长的PDF文档整篇需要翻译,怎么办呢? 二、腾讯交互翻译TranSmart https…

示例:WPF中应用DependencyPropertyDescriptor监视依赖属性值的改变

一、目的&#xff1a;开发过程中&#xff0c;经常碰到使用别人的控件时有些属性改变没有对应的事件抛出&#xff0c;从而无法做处理。比如TextBlock当修改了IsEnabled属性我们可以用IsEnabledChanged事件去做对应的逻辑处理&#xff0c;那么如果有类似Background属性改变我想找…

构建未来应用的核心,云原生技术栈解析

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、云原生技术栈 1、容器和容器编排 1.1 Docker 1.2 Kubernete…

如何在Android中实现多线程与线程池?

目录 一、Android介绍二、什么是多线程三、什么是线程池四、如何在Android中实现多线程与线程池 一、Android介绍 Android是一种基于Linux内核的开源操作系统&#xff0c;由Google公司领导开发。它最初于2007年发布&#xff0c;旨在为移动设备提供一种统一、可扩展的操作系统。…

朴素贝叶斯案例

一、朴素贝叶斯算法&#xff1a; 朴素贝叶斯算法&#xff0c;是一种基于贝叶斯定理与特征条件独立假设的分类方法&#xff0c;基于贝叶斯后验概率建立的模型&#xff0c;它用于解决分类问题。朴素&#xff1a;特征条件独立&#xff1b;贝叶斯&#xff1a;基于贝叶斯定理。属于…

【论文精读】分类扩散模型:重振密度比估计(Revitalizing Density Ratio Estimation)

文章目录 一、文章概览&#xff08;一&#xff09;问题的提出&#xff08;二&#xff09;文章工作 二、理论背景&#xff08;一&#xff09;密度比估计DRE&#xff08;二&#xff09;去噪扩散模型 三、方法&#xff08;一&#xff09;推导分类和去噪之间的关系&#xff08;二&a…

数组 (java)

文章目录 一维数组静态初始化动态初始化 二维数组静态初始化动态初始化 数组参数传递可变参数关于 main 方法的形参 argsArray 工具类sort 中的 comparable 和 comparatorcomparator 比较器排序comparable 自然排序 一维数组 线性结构 静态初始化 第一种&#xff1a;int[] a…

[系统运维|Xshell]宿主机无法连接上NAT网络下的虚拟机进行维护?主机ping不通NAT网络下的虚拟机,虚拟机ping的通主机!解决办法

遇到的问题&#xff1a;主机ping不通NAT网络下的虚拟机&#xff0c;虚拟机ping的通主机 服务器&#xff1a;Linux&#xff08;虚拟机&#xff09; 主机PC&#xff1a;Windows 虚拟机&#xff1a;vb&#xff0c;vm测试过没问题&#xff0c;vnc没测试不清楚 虚拟机网络&#xff1…

Vue的Router?一个小demo秒了

效果展示 正文 登录页 <template><div><div class"login"><h3>图书管理系统</h3><div class"user"><span>账号&#xff1a;</span><input type"text" v-model"user" /></…

ClickHouse备份方案

ClickHouse备份方案主要包括以下几种方法&#xff1a; 一、使用clickhouse-backup工具&#xff1a; &#xff08;参考地址&#xff1a;https://blog.csdn.net/qq_43510111/article/details/136570850&#xff09; **安装与配置&#xff1a;**首先从GitHub获取clickhouse-bac…

Node.js是什么(基础篇)

前言 Node.js是一个基于Chrome V8 JavaScript引擎的开源、跨平台JavaScript运行时环境&#xff0c;主要用于开发服务器端应用程序。它的特点是非阻塞I/O模型&#xff0c;使其在处理高并发请求时表现出色。 一、Node JS到底是什么 1、Node JS是什么 Node.js不是一种独立的编程…

vue3页面传参

一&#xff0c;用query传参 方法&#xff1a; router.push({path: ‘路由地址’, query: ‘参数’}) 例子&#xff1a;a页面携带参数跳转到b页面并且b页面拿到a页面传递过来的参数 在路由router.ts配置 a页面&#xff1a; <template><div >a页面</div>…

基于YOLOv5的火灾检测系统的设计与实现(PyQT页面+YOLOv5模型+数据集)

基于YOLOv5的火灾检测系统的设计与实现 概述系统架构主要组件代码结构功能描述YOLOv5检测器视频处理器主窗口详细代码说明YOLOv5检测器类视频处理类主窗口类使用说明环境配置运行程序操作步骤检测示例图像检测视频检测实时检测数据集介绍数据集获取数据集规模YOLOv5模型介绍YOL…

测试辅助工具(抓包工具)的使用2 之 抓包工具的基本用法

1.过滤设置: Filters- --- 勾选use Filters- --- 下拉选择show only the following hosts ---- 输入域名或者ip地址(多个地址用;隔开) --- 点击action(Run filterset now) 2.删除数据 方式一:点击Remove all 方式二: 黑窗口输入cls,回车 删除一条数据:选中数据---右键选择Rem…

【硬件开发】共模电感

为什么电源无论直流还是交流的输入端都需要一个共模电感 图中L1就是共模电感&#xff0c;长下面这个样子&#xff0c;两侧的匝数&#xff0c;线径和材料都是一模一样的 共模电感的作用是为了抑制共模信号 抑制共模信号工作原理 http://【共模电感是如何抑制共模信号的】https…

SpringCloud - 微服务

1、微服务介绍 参考&#xff1a; 微服务百度百科 1.1 概念 微服务&#xff08;或称微服务架构&#xff09;是一种云原生架构方法&#xff0c;在单个应用中包含众多松散耦合且可单独部署的小型组件或服务。 这些服务通常拥有自己的技术栈&#xff0c;包括数据库和数据管理模型&…

windows git配置多个账号

window下git多账号配置_百度搜索 (baidu.com) 最重要的是这里生成新的id_rsa文件的时候&#xff0c;bash窗口是在 .ssh路径下 其实就是这个窗口在什么路径下执行的就是生成在什么路径 下面窗口路径不对&#xff0c;不是Desktop&#xff0c;应该是.ssh 如果是Desktop或者任何一…

YOLOv9摄像头或视频实时检测

1、下载yolov9的项目 地址&#xff1a;YOLOv9 2、使用下面代码进行检测 import torch import cv2 from models.experimental import attempt_load from utils.general import non_max_suppression, scale_boxes from utils.plots import plot_one_box# 加载预训练的YOLOv9模型…

CausalMMM:基于因果结构学习的营销组合建模

1. 摘要 在线广告中&#xff0c;营销组合建模&#xff08;Marketing Mix Modeling&#xff0c;MMM&#xff09; 被用于预测广告商家的总商品交易量&#xff08;GMV&#xff09;&#xff0c;并帮助决策者调整各种广告渠道的预算分配。传统的基于回归技术的MMM方法在复杂营销场景…

Kubernetes排错(七)-Pod 状态一直 ContainerCreating

查看 Pod 事件 $ kubectl describe pod apigateway-6dc48bf8b6-l8xrw -n cn-staging 异常原因 1&#xff09;no space left on device ... Events:Type Reason Age From Message---- ------ …