无代理安装k8s

安装Kubernetes在国内网络环境中是一个非常困难的事情,因为首先kubelet等二进制文件需要在github等网站上下载,
然后很多镜像是在国内很难访问的。通常大型的公司解决这种问题都是引入一个透明的网关,但是个人开发者在
云服务器上显然没有这种条件。本文旨在解决没有服务器代理的条件下在国内网络中安装 Kubernetes 的问题。

背景

k8s需要很多镜像,但是这些镜像有很多分部在 gcr.io、k8s.gcr.io 等站点上,而国内几乎无法下载这些站点上的内容。
当前存在部分的 docker.io 的镜像站,包括:

  • mirrors.ustc.edu.cn
  • mirror.ccs.tencentyun.com (腾讯云内网可用)
  • 阿里云的私有镜像地址

然而 gcr.io 和 quay.io 并没有对应的镜像站

安装步骤

我们使用的方案是 k0s,它可以比较方便地安装和配置集群。

安装 containerd,在不是太老的发行版上都能比较方便地安装 containerd,这步在此不详细赘述

安装 k0s

安装 k0s,k0s可以在 github release 上下载,这里有两种方法,一种是在本地机器上下好然后 scp 到云服务器,另一种方法是使用一些
github 镜像站辅助下载 k0s,这些镜像站包括:

成功下载之后只需要 cp 到 /usr/local/bin,并且赋予执行权限就行。然后 k0s 就安装完成了。

配置 k0s

直接部署在国内当然是不行的,我们需要定制 k0s 的安装镜像。先生成一份 k0s 的配置文件:

1
2
sudo mkdir -p /etc/k0s
k0s config create | sudo tee /etc/k0s/k0s.yaml

编辑 /etc/k0s/k0s.yaml,找到里面 images,会发现里面有很多 gcr.io 和 quay.io 的镜像,我们需要处理这些镜像,
处理的方法是将这些镜像 push 到 docker.io 中,这样我们就可以通过 registry mirror 来快速地下载获取这些镜像。
当然我们不必要手动做这些事情,github 上有部分项目可以帮我们完成这部分工作:

把所有配置文件中的 gcr.io 和 quay.io 的镜像使用如上方法进行搬运,并且替换配置文件中的镜像名称

配置 containerd

(这里首先假设你使用的 CRI 是 containerd)
首先根据 k0s 的文档,生成默认的配置文件:

1
containerd config default | sudo tee /etc/k0s/containerd.toml

然后根据 k0s 的文档进行修改:

1
2
3
4
5
6
7
version = 2
root = "/var/lib/k0s/containerd"
state = "/run/k0s/containerd"
...

[grpc]
address = "/run/k0s/containerd.sock"

然后修改 docker.io 的 registry mirror:

1
2
3
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirror.ccs.tencentyun.com","https://index.docker.io"]

请将腾讯云的 registry mirror 地址替换成你想要使用的 registry mirror 地址。

最后将 sandbox image 用相同的方法进行替换:

1
2
3
[plugins."io.containerd.grpc.v1.cri"]
...
sandbox_image = "anjia0532/google-containers.pause:3.5"

启动 k0s

执行:

1
2
sudo k0s install controller -c /etc/k0s/k0s.yaml
sudo k0s start

然后观察 k0s 的日志输出:

1
journalctl -u k0scontroller.service -f

如果没有观察到长时间没有自行解决的问题,那么说明 k8s 部署成功

配置文件

最后贴一下配置文件,k0s 版本为 v1.25.2+k0s.0,containerd 版本为 1.5.11

/etc/k0s/containerd.toml

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
disabled_plugins = []
imports = []
oom_score = 0
plugin_dir = ""
required_plugins = []
root = "/var/lib/k0s/containerd"
state = "/var/lib/k0s/run/containerd"
version = 2

[cgroup]
path = ""

[debug]
address = ""
format = ""
gid = 0
level = ""
uid = 0

[grpc]
address = "/var/lib/k0s/run/containerd.sock"
gid = 0
max_recv_message_size = 16777216
max_send_message_size = 16777216
tcp_address = ""
tcp_tls_cert = ""
tcp_tls_key = ""
uid = 0

[metrics]
address = ""
grpc_histogram = false

[plugins]

[plugins."io.containerd.gc.v1.scheduler"]
deletion_threshold = 0
mutation_threshold = 100
pause_threshold = 0.02
schedule_delay = "0s"
startup_delay = "100ms"

[plugins."io.containerd.grpc.v1.cri"]
disable_apparmor = false
disable_cgroup = false
disable_hugetlb_controller = true
disable_proc_mount = false
disable_tcp_service = true
enable_selinux = false
enable_tls_streaming = false
ignore_image_defined_volumes = false
max_concurrent_downloads = 3
max_container_log_line_size = 16384
netns_mounts_under_state_dir = false
restrict_oom_score_adj = false
sandbox_image = "anjia0532/google-containers.pause:3.5"
selinux_category_range = 1024
stats_collect_period = 10
stream_idle_timeout = "4h0m0s"
stream_server_address = "127.0.0.1"
stream_server_port = "0"
systemd_cgroup = false
tolerate_missing_hugetlb_controller = true
unset_seccomp_profile = ""

[plugins."io.containerd.grpc.v1.cri".cni]
bin_dir = "/opt/cni/bin"
conf_dir = "/etc/cni/net.d"
conf_template = ""
max_conf_num = 1

[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "runc"
disable_snapshot_annotations = true
discard_unpacked_layers = false
no_pivot = false
snapshotter = "overlayfs"

[plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]
base_runtime_spec = ""
container_annotations = []
pod_annotations = []
privileged_without_host_devices = false
runtime_engine = ""
runtime_root = ""
runtime_type = ""

[plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options]

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
base_runtime_spec = ""
container_annotations = []
pod_annotations = []
privileged_without_host_devices = false
runtime_engine = ""
runtime_root = ""
runtime_type = "io.containerd.runc.v2"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
BinaryName = ""
CriuImagePath = ""
CriuPath = ""
CriuWorkPath = ""
IoGid = 0
IoUid = 0
NoNewKeyring = false
NoPivotRoot = false
Root = ""
ShimCgroup = ""
SystemdCgroup = false

[plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime]
base_runtime_spec = ""
container_annotations = []
pod_annotations = []
privileged_without_host_devices = false
runtime_engine = ""
runtime_root = ""
runtime_type = ""

[plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime.options]

[plugins."io.containerd.grpc.v1.cri".image_decryption]
key_model = "node"

[plugins."io.containerd.grpc.v1.cri".registry]
config_path = ""

[plugins."io.containerd.grpc.v1.cri".registry.auths]

[plugins."io.containerd.grpc.v1.cri".registry.configs]

[plugins."io.containerd.grpc.v1.cri".registry.headers]

[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirror.ccs.tencentyun.com","https://index.docker.io"]

[plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming]
tls_cert_file = ""
tls_key_file = ""

[plugins."io.containerd.internal.v1.opt"]
path = "/opt/containerd"

[plugins."io.containerd.internal.v1.restart"]
interval = "10s"

[plugins."io.containerd.metadata.v1.bolt"]
content_sharing_policy = "shared"

[plugins."io.containerd.monitor.v1.cgroups"]
no_prometheus = false

[plugins."io.containerd.runtime.v1.linux"]
no_shim = false
runtime = "runc"
runtime_root = ""
shim = "containerd-shim"
shim_debug = false

[plugins."io.containerd.runtime.v2.task"]
platforms = ["linux/amd64"]

[plugins."io.containerd.service.v1.diff-service"]
default = ["walking"]

[plugins."io.containerd.snapshotter.v1.aufs"]
root_path = ""

[plugins."io.containerd.snapshotter.v1.btrfs"]
root_path = ""

[plugins."io.containerd.snapshotter.v1.devmapper"]
async_remove = false
base_image_size = ""
pool_name = ""
root_path = ""

[plugins."io.containerd.snapshotter.v1.native"]
root_path = ""

[plugins."io.containerd.snapshotter.v1.overlayfs"]
root_path = ""

[plugins."io.containerd.snapshotter.v1.zfs"]
root_path = ""

[proxy_plugins]

[stream_processors]

[stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
path = "ctd-decoder"
returns = "application/vnd.oci.image.layer.v1.tar"

[stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
path = "ctd-decoder"
returns = "application/vnd.oci.image.layer.v1.tar+gzip"

[timeouts]
"io.containerd.timeout.shim.cleanup" = "5s"
"io.containerd.timeout.shim.load" = "5s"
"io.containerd.timeout.shim.shutdown" = "3s"
"io.containerd.timeout.task.state" = "2s"

[ttrpc]
address = ""
gid = 0
uid = 0

/etc/k0s/k0s.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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

apiVersion: k0s.k0sproject.io/v1beta1
kind: ClusterConfig
metadata:
creationTimestamp: null
name: k0s
spec:
api:
.....
tunneledNetworkingMode: false
controllerManager: {}
extensions:
helm:
charts: null
repositories: null
storage:
create_default_storage_class: false
type: external_storage
images:
calico:
cni:
image: docker.io/calico/cni
version: v3.24.1
kubecontrollers:
image: docker.io/calico/kube-controllers
version: v3.24.1
node:
image: docker.io/calico/node
version: v3.24.1
coredns:
image: docker.io/coredns/coredns
version: 1.9.4
default_pull_policy: IfNotPresent
konnectivity:
image: togettoyou/quay.io.k0sproject.apiserver-network-proxy-agent
version: 0.0.32-k0s1
kubeproxy:
image: anjia0532/google-containers.kube-proxy
version: v1.25.2
kuberouter:
cni:
image: docker.io/cloudnativelabs/kube-router
version: v1.5.1
cniInstaller:
image: togettoyou/quay.io.k0sproject.cni-node
version: 1.1.1-k0s.0
metricsserver:
image: anjia0532/google-containers.metrics-server.metrics-server
version: v0.6.1
pushgateway:
image: togettoyou/quay.io.k0sproject.pushgateway-ttl
version: edge
installConfig:
users:
etcdUser: etcd
kineUser: kube-apiserver
konnectivityUser: konnectivity-server
kubeAPIserverUser: kube-apiserver
kubeSchedulerUser: kube-scheduler
konnectivity:
adminPort: 8133
agentPort: 8132
network:
calico: null
clusterDomain: cluster.local
dualStack: {}
kubeProxy:
mode: iptables
kuberouter:
autoMTU: true
hairpinMode: false
metricsPort: 8080
mtu: 0
peerRouterASNs: ""
peerRouterIPs: ""
podCIDR: 10.244.0.0/16
provider: kuberouter
serviceCIDR: 10.96.0.0/12
scheduler: {}
storage:
etcd:
externalCluster: null
peerAddress: 10.206.0.9
type: etcd
telemetry:
enabled: true
status: {}
知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。