0%

安装CRI-O

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 设置环境变量
OS=Debian_11
VERSION=1.27

# 添加源
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list

# 导入key
curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | apt-key add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -

# 更新
apt-get update

# 安装 cri-o
apt-get install cri-o cri-o-runc

# 启动cri-o
service crio start

安装Kubernetes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# disable swap
swapoff -a
# 编辑 /etc/fstab 去掉 swap 的配置

# 配置启动加载模块
modprope br_netfilter
# 在 /etc/modules 追加 br_netfilter,以便重启后自动加载 br_netfilter

# 配置
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-arptables = 1
EOF
sysctl --system

# install k8s,k8s的版本需要与crio的版本对应,crio是1.27的,k8s的也是1.27
apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -

echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list

KUBE_VERSION=1.27.1-00
apt-get update
apt-get install -y kubelet=$KUBE_VERSION kubeadm=$KUBE_VERSION kubectl=$KUBE_VERSION
# 锁定版本
apt-mark hold kubelet kubeadm kubectl

配置Kubernetes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 使用kubeadm初始化
PUBLICIP=xxx.xxx.xxx.xxx
kubeadm init --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/16 --apiserver-advertise-address=$PUBLICIP --cri-socket=/var/run/crio/crio.sock
# 如果不需要设定publicip,可以省略这参数

# 配置
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

# 安装网络插件
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

# 确认下是否配置成功
kubectl get nodes -n kube-system
kubectl get pods -n kube-system

# 配置 dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
# 配置 dashboard访问用户参考
# https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md

配置环境

  1. VSCode,安装 Flutter Intf 插件

image-20220218123823301

  1. 打开工程,初始化模块

image-20220218123930926

初始化后,会在lib目录中看到

1
2
3
4
5
6
lib
- generated
- intl
- l10n.dart
- l10n
- intl_en.arb

根据需要,通过 >Flutter Intl: Add locale 添加需要支持的语言

image-20220218124131700

添加后,会在 l10n 目录下看到 intl_xx_xx.arb 的资源文件,需要使用的文案往里面添加即可。

使用资源

在初始化MaterialApp的代码中,添加国际化的支持

1
2
3
4
5
6
7
8
9
10
11
return MaterialApp(
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
locale: model.locale, // Locale("en", "US"), Locale("zh", "CN") 等等
home: const MyHomePage(),
);

在后面的Widget中,可以通过context来获取对应的文案

1
S.of(context).xxx 

前置知识

Kubernetes部署Gitea+Drone+Registry

因为作者的Gitea是部署在k8s上,所以这次配置的 govanityurls 也是在k8s上构建,前置的环境不做多说。

构建govanityurls镜像

源代码:https://github.com/GoogleCloudPlatform/govanityurls

拉取源代码后,执行 go build 即可。

然后配置 Dockerfile 构建镜像,推送的自己的代码仓库中。

1
2
3
4
5
FROM alpine:3.13.5
WORKDIR /app
COPY ./govanityurls .
EXPOSE 8080
CMD /app/govanityurls

如果不想自己构建,可以直接使用其他人构建好的,例如下面的

1
garukun/govanityurls:latest

在k8s配置 govanityurls

创建 deployment.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
apiVersion: apps/v1
kind: Deployment
metadata:
name: govanityurls
spec:
replicas: 1
selector:
matchLabels:
app: govanityurls
template:
metadata:
labels:
app: govanityurls
spec:
imagePullSecrets:
- name: regcred
containers:
- name: govanityurls
image: code-registry.domain/govanityurls:v0.1
# 因为我的镜像程序是在 /app/govanityurls , 配置挂载在 /app/config/vanity.yaml
command: [ "/app/govanityurls", "/app/config/vanity.yaml" ]
ports:
- containerPort: 8080
name: http
volumeMounts:
- name: static-pvc
mountPath: "/app/config"
subPath: "govanityurls"
restartPolicy: "Always"
volumes:
- name: static-pvc
persistentVolumeClaim:
claimName: static-pvc

创建 ingress.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apiVersion: v1
kind: Service
metadata:
name: govanityurls
labels:
app: govanityurls
spec:
selector:
app: govanityurls
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: govanityurls-ingress
spec:
rules:
- host: pkg.domain
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: govanityurls
port:
number: 8080

配置包路径 vanity.yaml

1
2
3
4
5
6
host: pkg.domain

paths:
/libcomm:
repo: https://gitcode.domain/user/libcomm
vcs: git

参数解说

  1. host,包的域名。例如创建的一个libcomm的包,go引用的路径就是 pkg.domain/libcomm
  2. paths中的repo,git的仓库路径,可以是 https:

例如在gitea中,使用user,创建一个libcomm的仓库,git的https连接为

1
https://gitcode.domain/user/libcomm.git

测试go包

创建仓库 libcomm

1
go mod init pkg.domain/libcomm

编写包代码

1
2
3
package libcomm

const TEST = 1

将代码提交到仓库中。

创建新的项目,测试引用包

1
2
3
4
5
6
7
8
9
package main
import (
"fmt"
"pkg.domain/libcomm"
)

func main() {
fmt.Println(libcomm.TEST)
}

通过 go get 拉取包

1
GIT_TERMINAL_PROMPT=1 go get -v pkg.domain/libcomm

注意:首次必须要追加 GIT_TERMINAL_PROMPT=1,因为私有代码仓库有用户密码验证,不添加这参数,会出现用户密码错误。

如果服务器不支持https ,可以追加 -insecure 参数。

1
go get -v -insecure pkg.domain/libcomm

最后,go build ,一切正常~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# updated: Mar 4 2022
# 上面 go get -insecure 方式已经废弃,会有报错信息
# fatal: could not read Username for xxx terminal prompts disabled
# 解决方法
# 编辑 .gitconfig 替换https访问方式,改成git方式访问私有库
# 将git的 https://git.host 访问地址改成 ssh访问方式
# 第一步
[url "ssh://git@<git.host>:"]
insteadOf = https://git.host
# 第二步
# 配置客户端ssh认证 ~/.ssh/config
# 第三步
# 将仓库标记为私有库
go env -w GOPRIVATE=pkg.domain/libcomm
# 解决,然后直接运行 go get pkg.domain/libcomm ~

参考资料
https://tonybai.com/2017/06/30/go-get-go-packages-in-private-code-repo-by-govanityurls/

https://github.com/GoogleCloudPlatform/govanityurls

https://erwinvaneyk.nl/private-repositories-with-go-mod/

使用CRIO时,POD创建的时候会出现失败,错误信息

Failed to create pod sandbox: rpc error: code = Unknown desc = cri-o configured with systemd cgroup manager, ...

是因为默认情况,CRIO使用的是 cgroupfs(bug),这里需要手动配置一下。

编辑 /var/lib/kubelet/kubeadm-flags.env 追加 –cgroup-driver=systemd 参数

然后重新启动

1
2
systemctl daemon-reload
systemctl restart kubelet

参考

https://github.com/cri-o/cri-o/issues/896

Docker-compose 配置 rabbitmq-management

带管理面板的rabbitmq,直接加载镜像,管理面板的http端口是 15672,直接拉取镜像就行。

1
2
3
4
5
6
7
8
9
10
11
12
13
version: '3'

services:
rabbitmq:
image: rabbitmq:3.8.14-management-alpine
container_name: rabbitmq
ports:
- 8080:15672
volumes:
- rabbitmq-data:/var/lib/rabbitmq

volumes:
rabbitmq-data:

然后打开 http://localhost:8080/ 初始化用户密码是 guest/guest 。

配置 rabbitmq-management with ssl

  1. 生成证书

直接使用脚本,比较方便 https://github.com/Berico-Technologies/CMF-AMQP-Configuration

1
2
3
4
5
6
7
8
git clone https://github.com/Berico-Technologies/CMF-AMQP-Configuration
cd CMF-AMQP-Configuration/ssl
# MyRabbitMQCA 是自定义CA的名称
sh setup_ca.sh MyRabbitMQCA
# rabbitmq-server 服务器hostname rabbit 是密码
sh make_server_cert.sh rabbitmq rabbit
# rabbit-client 客户端标识 rabbit 是密码
sh create_client_cert.sh rabbit-client rabbit

注意

1)服务器证书的CN需要与hostname一致,不然在创建tls连接时会失败。

2)这个脚本直接创建,通过golang 创建tls连接时,会出现

failed to connect rabbitmq!:x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

这个错误。处理方式有两种

A. 修正证书的SAN

B. 通过GODEBUG设置x509ignoreCN=0 忽略

B的方式虽然更简单,但是这种绕过的方式必然不是解决方案。

那怎么修正 SAN 呢,参考下面的步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
# 进入 CMF-AMQP-Configuration/ssl 编辑 openssl.conf
# 找到 [ req ] 在末尾添加
req_extensions = v3_req
# 然后在末尾添加 标签 [ v3_req ] [ alt_names ]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = localhost
DNS.2 = rabbitmq
# 这里的DNS就是证书对应的域名,按需要来添加,目前例子中是 rabbitmq,就这么填。这里支持通配符 *,可以做多域名支持

修改 make_server_cert.sh 脚本

1
2
3
4
5
6
7
8
9
# 找到创建证书的地方
openssl req -new -key $sname.key.pem -out $sname.req.pem -outform PEM -subj /CN=$sname/O=server/ -nodes

openssl ca -in ../server/$sname.req.pem -out ../server/$sname.cert.pem -notext -batch -extensions server_ca_extensions

# 追加 -extensions v3_req
openssl req -new -key $sname.key.pem -out $sname.req.pem -outform PEM -subj /CN=$sname/O=server/ -nodes -extensions v3_req

openssl ca -in ../server/$sname.req.pem -out ../server/$sname.cert.pem -notext -batch -extensions server_ca_extensions -extensions v3_req

修改客户端证书,同样

1
2
3
4
5
6
7
# 找到下面两行
openssl req -new -key $cname.key.pem -out $cname.req.pem -outform PEM -subj /CN=$cname/O=client/ -nodes
openssl ca -in ../client/$cname.req.pem -out ../client/$cname.cert.pem -notext -batch -extensions client_ca_extensions

# 追加 -extensions v3_req
openssl req -new -key $cname.key.pem -out $cname.req.pem -outform PEM -subj /CN=$cname/O=client/ -nodes -extensions v3_req
openssl ca -in ../client/$cname.req.pem -out ../client/$cname.cert.pem -notext -batch -extensions client_ca_extensions -extensions v3_req

然后重新生成一遍证书

执行脚本后,复制证书文件,只需要5个。

cacert.pem

rabbitmq.cert.pem 服务端证书

rabbitmq.key.pem 服务端拿证书

rabbitmq-client.cert.pem 客户端证书

rabbitmq-client.key.pem 客户端证书

将文件复制到 cert 目录中,docker-compose 目录结构如下

1
2
3
4
5
6
7
8
9
rabbitmq-folder
|-- docker-compose.yaml
|-- rabbitmq.conf
|-- cert
|-- cacert.pem
|-- rabbitmq.cert.pem
|-- rabbitmq.key.pem
|-- rabbitmq-client.cert.pem
|-- rabbitmq-client.key.pem

到此为止,证书处理完成。

  1. 配置 rabbitmq.conf
1
2
3
4
5
6
7
8
9
loopback_users.guest = false
listeners.ssl.default = 5671
ssl_options.cacertfile = /cert/cacert.pem
ssl_options.certfile = /cert/rabbitmq.cert.pem
ssl_options.fail_if_no_peer_cert = true
ssl_options.keyfile = /cert/rabbitmq.key.pem
ssl_options.verify = verify_peer

management.tcp.port = 15672
  1. 配置compose
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version: '3'

services:
rabbitmq:
image: rabbitmq:3.8.14-management-alpine
container_name: rabbitmq
hostname: rabbitmq
ports:
- 8080:15672
volumes:
- rabbitmq-data:/var/lib/rabbitmq
- ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
- ./cert:/cert

volumes:
rabbitmq-data:

然后唤起验证

打开浏览器

image-20210330041852295

看到 amqp/ssl 5671 , 配置正常。

后语

在 rabbitmq 的镜像中,可以通过 environment 环境变量,设置

RABBITMQ_MANAGER_SSL_CACERTFILE
RABBITMQ_MANAGEMENT_SSL_CERTFILE
RABBITMQ_MANAGEMENT_SSL_KEYFILE

参考:https://hub.docker.com/_/rabbitmq

来配置证书,但是个人并不喜欢直接这么配置,因为直接使用这个,默认情况management plugin 也会开启了ssl。对于自签证书来说,并不方便。

个人更偏好 management plugin 是 http协议的,外层 nginx 统一处理 ssl 证书。

加上本身rabbitmq的配置文件也是需要自定义的,直接在配置文件修改就行,没必要通过环境变量来设置。


相关资料

rabbitmq镜像 https://hub.docker.com/_/rabbitmq

golang 自签证书双向认证 https://studygolang.com/articles/31646