2.3 公共服务
在没有使用容器前,笔者经常还没运行起要部署的程序,就先卡在依赖项的配置上,比如 MySQL 和 Redis。
而有了容器之后,虽然可以跳过编译代码和安装软件包,但重复配置这些常用依赖也是一件让人头痛的问题,因此有必要提前规划,将常用的软件单独部署为公共服务,这也能减少资源占用。
笔者常用的就有 MySQL、Postgres、Minio、Redis,这里约定固定在 storage 命名空间下部署这些主要用于存储数据的应用。
下面主要使用 statefulset 和 service 部署应用,应用的数据通过 local-pv 存储在本地。
使用 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;
使用 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;
Minio 是一个开源的 S3 存储服务,许多开源软件,如 harbor、bookstack 等,都支持使用 S3 协议存储数据,这样就不需要配置本地存储,实现无状态化部署,便于水平扩缩容。
minio 进程会监听两个端口,--address
指定 S3 协议端口,这里设置为 9000,--console-address
指定网页控制台端口,这里设置为 9001。
另外有四个环境变量需配置:
- MINIO_ROOT_USER:管理员用户名
- MINIO_ROOT_PASSWORD:管理员密码
- MINIO_SERVER_URL:S3 协议 URL
- 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:
这里使用 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
...