问题描述
当使用 kubeadm 命令初始化集群时,会去官方镜像仓库(k8s.gcr.io)拉取镜像。但是国内网络无法访问官方镜像仓库,导致集群初始化失败;
该笔记将记录:在 Kubernetes 集群初始化时,拉取官方镜像的方法;
解决方案
简而言之,我们推荐使用如下方式:
通用场景:crane, gcrane, krane
通过 crane cp 命令,能够将镜像复制到自建仓库中:
crane auth login -u username -p password registry.example.com crane cp \ registry.k8s.io/ingress-nginx/controller:v1.2.1 \ registry.example.com/ingress-nginx/controller:v1.2.1 # 在 Harbor 中,crane 无法使用多级镜像路径,即 registry.example.com/a/b/c/ingress-nginx/controller:v1.2.1 将失败;
特性特征:
1)能够识别 HTTP_PROXY HTTPS_PROXY NO_PROXY 等等环境变量;
2)无需运行 docker 服务;
复制镜像,并保存摘要(镜像摘要发生变化)
go-containerregistry/crane.md at main · google/go-containerregistry · GitHub
我们现在发现的问题是
1)通过 docker inspect --format='{{index .RepoDigests 0}}' $IMAGE 会发现多个摘要;
2)当推送镜像后,将仅保留当前仓库的 Digest 信息,而原始仓库的 Digest 信息将不会被推送到当前仓库中;
通过 crane cp 命令,能够解决该问题;
针对 Kubernetes 集群:新版集群(推荐)
在使用 kubeadm v1.14 初始化集群时,我们无意间发现它支持 --image-repository 选项,该选项能够指定镜像仓库地址:
kubeadm init --image-repository registry.aliyuncs.com/google_containers
如果通过配置文件初始化集群,能够使用 imageRepository 字段
针对 Kubernetes 集群:手动拉取镜像
我学到的首个方法是手动拉取镜像,然后在本地打标签。因为如果镜像存在于本地,则 kubeadm 将不再去官方拉取镜像,因此该方法可行;
第一步、查看需要拉取的镜像
首先需要知道拉取那些镜像:
#!/bin/sh kubeadm config images list # 而上述命令会卡顿,因为它需要访问 dl.k8s.io 地址获取版本。你可以手动指定版本: kubeadm config images list --kubernetes-version 1.12.10
命令会产生类似如下输出:
k8s.gcr.io/kube-apiserver:v1.12.10 k8s.gcr.io/kube-controller-manager:v1.12.10 k8s.gcr.io/kube-scheduler:v1.12.10 k8s.gcr.io/kube-proxy:v1.12.10 k8s.gcr.io/pause:3.1 k8s.gcr.io/etcd:3.2.24 k8s.gcr.io/coredns:1.2.2
第二步、拉取目标镜像到本地
根据上面输出,我们已经得知所有需要拉取的镜像。接下来我们以kube-apiserver:v1.12.10为例;
在 Docker Hub 中(或者其他地方)找到kube-apiserver:v1.12.10镜像,并拉取到本地:
# 我们随便拉取一个 docker pull imdingtalk/kube-apiserver:v1.12.10
第三步、使用官方镜像标签
docker tag imdingtalk/kube-apiserver:v1.12.10 k8s.gcr.io/kube-apiserver:v1.12.10
第四步、推送到私有仓库(可选)
建议将镜像推送到本地私有奖项仓库,预备日后使用。另外,以可以防止官方镜像无法访问等问题;
拉取“官方镜像”到本地,并推送私有仓库
以下脚本用于处理与镜像有关的问题:
1)将官方镜像拉取到本地,解决镜像无法拉取问题;
2)将镜像推送到私有仓库,进行备份;
通常某个用户会提供所有相关镜像。可以使用如下脚本从 imdingtalk 中拉取所有镜像,并创建标签:
dockerhub_username="imdingtalk" kubernetes_version="1.12.10" private_registry_prefix="10.10.50.4/k8s" for img in $(kubeadm config images list --kubernetes-version "${kubernetes_version}") do echo "### $img" # 获取原始镜像名 img_name=$(echo $img | sed 's%k8s.gcr.io/%%g') # 从 Docker Hub 中拉取镜像 docker pull "${dockerhub_username}/${img_name}" # 为镜像创建新的标签 docker tag "${dockerhub_username}/${img_name}" "k8s.gcr.io/${img_name}" # 为了防止官方镜像日后无法访问,我们有必要对镜像进行备份: docker tag "${dockerhub_username}/${img_name}" "${private_registry_prefix}/${img_name}" docker push "${private_registry_prefix}/${img_name}" done
针对 Kubernetes 集群:旧版方法(使用旧版集群)
对于旧版集群,比如 1.12.1 版本。现在需要升级集群,它不支持 --image-repository 选项,因此你可以使用“方法一”。但是呢,我们还有其他办法,可能比较复杂,但更加通用;
第一步、导出默认配置
当我们执行kubeadm init时,集群便开始初始化。但是在内部它有默认配置文件,该配置文件可以使用kubeadm config print-default命令查看(新版需要使用kubeadm config print命令)。然后在配置文件中搜索imageRepository字段。是的,这就是默认镜像仓库地址;
第二步、修改默认配置
将上面imageRepository字段修改为可用的镜像仓库,保存并退出;
第三步、使用配置文件
在 kubeadm 中,很多子命令(config、init、upgrade)都支持--config选项,而该选项参数则为前面的配置文件;
比如集群升级命令,我们使用修改过的配置文件:
kubeadm upgrade apply v1.12.10 --config kubeadm-config.default.v1alpha3-aliyun
(当然,我们仅修改imageRepository字段)