安装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: {}
|