Atlantis
GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

2.3 公共服务

1. 前言

在没有使用容器前,笔者经常还没运行起要部署的程序,就先卡在依赖项的配置上,比如 MySQL 和 Redis。

而有了容器之后,虽然可以跳过编译代码和安装软件包,但重复配置这些常用依赖也是一件让人头痛的问题,因此有必要提前规划,将常用的软件单独部署为公共服务,这也能减少资源占用。

笔者常用的就有 MySQL、Postgres、Minio、Redis,这里约定固定在 storage 命名空间下部署这些主要用于存储数据的应用。

2. 部署公共数据存储

下面主要使用 statefulset 和 service 部署应用,应用的数据通过 local-pv 存储在本地。

2.1 MySQL

使用 dockerhub 上的 MySQL 8 容器镜像,并通过环境变量设置 root 用户密码为 password:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: storage
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: docker.io/library/mysql:8
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3306
          volumeMounts:
          - name: data
            mountPath: /var/lib/mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: password
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 5Gi
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: storage
spec:
  type: ClusterIP
  selector:
    app: mysql
  ports:
    - name: mysql
      port: 3306
      targetPort: 3306

启动容器后可以通过 kubectl exec 进入容器,登录 MySQL 数据库

➜  ~ kubectl -n storage exec mysql-0 -it -- mysql -hlocalhost -ppassword
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5499
Server version: 8.0.31 MySQL Community Server - GPL

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

创建一个与用户同名的数据库,并赋予所有权限,假设用户名和密码都为 bookstack:

create user 'bookstack'@'%' identified by 'bookstack';
create database bookstack;
GRANT ALL PRIVILEGES ON `bookstack`.* TO bookstack;
flush  privileges;

2.2 Postgres

使用 dockerhub 上的 PostgreSQL 15 容器镜像,并通过环境变量设置 postgres 用户密码为 password:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: storage
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: docker.io/library/postgres:15
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 5432
          volumeMounts:
          - name: data
            mountPath: /var/lib/postgresql/data
          env:
          - name: POSTGRES_PASSWORD
            value: password
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 5Gi
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: storage
spec:
  type: ClusterIP
  selector:
    app: postgres
  ports:
    - name: postgres
      port: 5432
      targetPort: 5432

启动容器后可以通过 kubectl exec 进入容器,登录 Postgres 数据库(postgres 用户通过本地登录时,无需输入密码):

➜  ~ kubectl -n storage exec postgres-0 -it -- psql -U postgres
psql (15.1 (Debian 15.1-1.pgdg110+1))
Type "help" for help.

postgres=# \l
                                                  List of databases
     Name      |  Owner   | Encoding |  Collate   |   Ctype    | ICU Locale | Locale Provider |   Access privileges
---------------+----------+----------+------------+------------+------------+-----------------+-----------------------
 postgres      | postgres | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            |
 template0     | postgres | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | =c/postgres          +
               |          |          |            |            |            |                 | postgres=CTc/postgres
 template1     | postgres | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | =c/postgres          +
               |          |          |            |            |            |                 | postgres=CTc/postgres
(8 rows)

postgres=#

创建一个与用户同名的数据库,并赋予所有权限,假设用户名和密码都为 bookstack:

CREATE DATABASE bookstack;
CREATE USER bookstack WITH PASSWORD 'bookstack';
ALTER DATABASE bookstack OWNER to bookstack;

2.3 Minio

Minio 是一个开源的 S3 存储服务,许多开源软件,如 harbor、bookstack 等,都支持使用 S3 协议存储数据,这样就不需要配置本地存储,实现无状态化部署,便于水平扩缩容。

minio 进程会监听两个端口,--address 指定 S3 协议端口,这里设置为 9000,--console-address 指定网页控制台端口,这里设置为 9001。

另外有四个环境变量需配置:

  1. MINIO_ROOT_USER:管理员用户名
  2. MINIO_ROOT_PASSWORD:管理员密码
  3. MINIO_SERVER_URL:S3 协议 URL
  4. MINIO_BROWSER_REDIRECT_URL:网页控制台 URL

最后需要挂载持久化存储到 /data 路径保存数据。

下面是一个完整示例,首先创建了一个 statefulset 运行 minio,然后通过 service 暴露服务,最后配置了公共 ingressroute 添加了两个域名分别映射到 service 的两个端口,如下:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: minio
  namespace: storage
spec:
  replicas: 1
  selector:
    matchLabels:
      app: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      containers:
        - name: minio
          image: docker.io/minio/minio:RELEASE.2022-09-25T15-44-53Z
          args: ["server", "/data", "--address", ":9000", "--console-address", ":9001"]
          env:
            - name: MINIO_ROOT_USER
              value: "minio"
            - name: MINIO_ROOT_PASSWORD
              value: "minio"
            - name: MINIO_SERVER_URL
              value: "https://s3.wbuntu.com"
            - name: MINIO_BROWSER_REDIRECT_URL
              value: "https://s3-console.wbuntu.com"
          ports:
            - containerPort: 9000
            - containerPort: 9001
          volumeMounts:
            - name: data
              mountPath: /data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 5Gi
---
apiVersion: v1
kind: Service
metadata:
  name: minio
  namespace: storage
spec:
  type: ClusterIP
  selector:
    app: minio
  ports:
    - name: s3
      port: 9000
      targetPort: 9000
    - name: s3-console
      port: 9001
      targetPort: 9001
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroute
  namespace: kube-system
spec:
  entryPoints:
  - websecure
  routes:
  ...
  - kind: Rule
    match: Host(`s3.wbuntu.com`)
    services:
    - name: minio
      namespace: storage
      port: 9000
  - kind: Rule
    match: Host(`s3-console.wbuntu.com`)
    services:
    - name: minio
      namespace: storage
      port: 9001
  ...
  tls:
    secretName: tls-cert

浏览器访问 s3.wbuntu.com 会就自动重定向到 s3-console.wbuntu.com,使用管理员账户登录后,可以在网页上管理用户和 bucket:

2.4 Redis

这里使用 dockerhub 上的 Redis 6 容器镜像,不设置密码:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
  namespace: storage
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: docker.io/library/redis:6
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 6379
          volumeMounts:
          - name: data
            mountPath: /data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 5Gi
---
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: storage
spec:
  type: ClusterIP
  selector:
    app: redis
  ports:
    - name: redis
      port: 6379
      targetPort: 6379

启动容器后可以通过 kubectl exec 进入容器,登录 Redis:

➜  ~ kubectl -n storage get pod redis-0
NAME      READY   STATUS    RESTARTS      AGE
redis-0   1/1     Running   9 (87d ago)   410d
➜  ~ kubectl -n storage exec redis-0 -it -- sh
# redis-cli
127.0.0.1:6379> info
# Server
redis_version:6.2.8
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:413feccb60252ec
redis_mode:standalone
os:Linux 4.19.0-26-cloud-amd64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:10.2.1
process_id:1
process_supervised:no
...