最近欠了好多的 blog,是在是有点忙,周末也被各种事情缠身。今天趁周日的最后半个小时抓紧记录下来一些调研的成果。
国内的网络环境大家都知道,一方面是不稳定的宽带,另一方面就是对一些国外网站访问的不可靠。今天集中记录一下自己在 docker 镜像处理方面的一些小技巧。
Docker 本身提供了一个叫做 docker registry mirror 的东西,就是为了减少重复的镜像下载所产生的额外带宽,在国内访问 docker 官方 image 极其缓慢的场景下这种需求尤为凸显。如果不设置相应的 mirror 国内服务器下载镜像真是举步维艰。
通过在 /etc/dockeer/daemon.json
做相应的配置就可以添加一个 registry mirror:
{
"registry-mirrors": ["<your registry mirror url>"]
}
配置之后需要重启 docker。
$ sudo pkill -SIGHUP dockerd
Docker 中国 估计是 docker 为了在中国开展业务搞的子公司吧?不应该是什么山寨网站吧。其提供了加速国内 docker pull 的镜像地址 https://registry.docker-cn.com。按照上述的配置方式配置即可使用:
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
然而很遗憾,这个速度并不理想,以我目前所在的网络环境,下行速度 4MB/s 拉取 ubuntu 镜像的速度大概也就是 400KB/s ~ 500KB/s。
daocloud 作为一个做 caas 的公司为国内提供了号称免费的 mirror 构建服务。登录控制台就可以看到如图所示的位置的加速器按钮了,点进去就有相应的脚本了。
注意 虽然人家是好意给了一个 shell 脚本帮助修改 /etc/docker/daemon.json 的配置,然而如果你的 docker 不止有一个 runtime,比如你像我这样需要跑 nvidia docker 的 runtime,那么这个脚本会把你的配置搞砸...建议直接想我这样手动配置:
{
"registry-mirrors": ["{{ docker_mirror }}"],
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
其中将 {{ docker_mirror }}
替换成 daocloud 提供的 mirror 即可。
配置之后重启 dockerd 感受下速度吧,同样的网络环境,基本是 2MB/s ~ 3MB/s。
上述的 docker-cn 以及 daocloud 仅仅是支持官方 docker.io 镜像的加速,然而要知道当今世界 google 的 google cloud platform 做的是相当不错,google 旗下的 kubernetes 基本是当前 PaaS 的不二之选,其官方镜像域名 gcr.io 下有大量 docker.io 无法取代的重要资源。而这些资源早早的已成为了墙外之物。
为了获取 gcr.io 域名下的镜像,我们可以在境外创建一个 vps 然后通过蚂蚁搬家的方式一点一点挪过来:
docker pull gcr.io/image-name:tage
docker tag gcr.io/image:tag <username>/image:tag
docker push <username>/image:tag
当然你可以写一个脚本,把自己用得着的镜像一个个 push 到 docker.io 中。甚至有人会写一些类似于 webhook 的东西,当 gcr.io 一些特定项目的镜像更新后会自动触发相应的流程自动托运新的镜像。不过不论如何这样的坏处显而易见:这是一个体力活,虽然有一些加速的脚本但是我依然需要更新脚本,管理 webhook...我先前已经用这个方法搞了一堆这样的镜像了...都是眼泪...
google 一下发现这种方式在用 kubeadam 安装 kubernetes 的场景被很多人采用了。
既然有了 vps 自然是可以直接搭建一个代理的,docker 本身是支持在 docker pull 使用代理的,那么配个代理不久解决问题了吗。具体怎么配置代理这里就不讲了,我只记录 docker 这边的配置:
首先 mkdir /etc/systemd/system/docker.service.d
。
然后创建 /etc/systemd/system/docker.service.d/http-proxy.conf
,添加内容如下:
[Service]
Environment="HTTP_PROXY=http://user01:[email protected]:8080/"
Environment="HTTPS_PROXY=https://user01:[email protected]:8080/"
Environment="NO_PROXY=localhost,.docker.io,.docker.com,.daocloud.io"
当然要使用自己的 HTTP_PROXY
和 HTTPS_PROXY
,然后把不想使用代理的域名添加到 NO_PROXY
,尤其是使用的镜像域名和 docker.io 应该考虑在内。
最后更新 systemctl 并重启服务
$ systemctl daemon-reload
$ systemctl restart docker
之后可以用以下镜像测试一下:
$ docker pull k8s.gcr.io/kube-scheduler-amd64:v1.10.2
在查找有关 docker proxy 内容时会发现有两种搜索结果,一种是我上述讲的 docker pull 时采用代理的方法;另一种是如何在 docker container 中配置代理:Configure Docker to use a proxy server 这个迷惑性还是有的...不过第二种情况以后也可能会用得上。
由于自己接触 docker 的时候和现在的 docker 不少的 api 已经有所变化,还是需要更新一下自己的知识。这篇文章大部分源自 docker 的官方文档,然后还有部分自己添油加醋。
在 docker 中所有的文件是存储在容器的 writable container layer
。存在以下的问题:
storage driver
采用了 union filesystem
效率低下然而 docker 提供了可以直接往 host 机器写内容的方式:
采用这些方式,即使容器关了甚至删除了数据依然不会丢失。
首先不论是采用哪种方式,在容器里看起来都是一样的。
/var/lib/docker/volumes
非 docker 无法使用Volume 可以通过 docker volume create
显式创建,当然 docker 也可以在运行的时候创建 volume(比如在 Dockerfile
里面有 VOLUME
语法时如果没有没有显式绑定 volume 那么就会默认创建一个新的 volume)。
docker volume create data
docker run -v data:/data ...
注意 docker volume inspect xxx
会得到如下的结果:
[
{
"CreatedAt": "2018-05-22T07:53:58Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/test/_data",
"Name": "test",
"Options": {},
"Scope": "local"
}
]
其存储的位置为 /var/lib/docker/volumes/test/_data
但是在 Mac OS 下你会发现根本没有这个目录,那是因为 Mac 下的 docker 还是以 linux 虚拟机的形式运行的,你所看到的是其虚拟机下的目录而不是 Mac 下的目录。
其功能相对 volume 比较有限。但是其好处是可以绑定任意的外部目录给 docker,尤其是在做一些外部数据共享给 docker 的时候非常适合。
docker run -v /tmp/data:/data:ro ...
我自己是没有直接使用过。基本就是用于沙盒环境吧。
docker run --tmpfs /data ...
两个特殊的场景:
最近一个多月开始折腾在 国内 环境部署 kubernetes 集群。是的,确实这还是一个工作内容,和直接在什么 aws googlecloud 或者是 rancher 2.0 直接点点就能创建有一个集群不一样。之所以还要付诸这样的精力去做这件事有两个原因:
不过因为我刚刚搞定了 aws 环境下 kubernetes 的部署,趁热打铁我就先记录一下这一部分。
k8s 有一个 cloud-provider
的概念,其目的是通过和一些公有云的服务集成以达到更好的功能。
aws 环境下的 k8s 是指 k8s 集成了部分 aws 的服务方便集群的使用。到目前为止,我所知道的包含如下内容:
LoadBalancer
类型的 service 绑定一个外部域名可以直接通过域名去访问而这篇文章则是重点介绍如何让 k8s 去支持这些特性,当然会缺少 kubeadm 一些信息,会在另外一篇介绍。
k8s 现在已经相当庞大,大的跟个操作系统似的。但是很遗憾其文档的成熟度还处于初级阶段,我甚至找不到 cloud-provider
配置的一些细节,唯一可靠的文档似乎就是代码,但是一不小心打开一个三四千行的 golang 文件我也是一脸迷茫...最后在一个诡异的 github issue 里面找到了一个 googledoc 解释了 cloud-provider=aws
的一些细节。
为了让 k8s 可以操纵 aws 的资源需要为 ec2 添加权限:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:*",
"elasticloadbalancing:*",
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:GetRepositoryPolicy",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:BatchGetImage",
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:UpdateAutoScalingGroup"
],
"Resource": "*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:GetRepositoryPolicy",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:BatchGetImage"
],
"Resource": "*"
}
]
}
为了识别具体哪些 ec2 是集群的一部分需要为每个 ec2 添加一个 KubernetesCluster
的 tag。
为了支持 cloud-provider 首先需要在 kubelet 的配置里做相应修改,为 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
添加 KUBELET_EXTRA_ARGS
:
[Service]
Environment="KUBELET_EXTRA_ARGS=--cloud-provider=aws
apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
cloudProvider: aws
api:
advertiseAddress: <internal-ip-address>
apiServerCertSANs:
- <public-ip-address>
- <public-hostname>
在用 kubeadm 创建集群时采用命令即可
kubeadm init --config=init-config.yaml
首先先要说明一下,aws 的机器默认的 hostname 是和其 internal dns hostname 不同。默认的是这个样子:
ip-xx-xx-xx-xx
而 internal hostname 则是
ip-xx-xx-xx-xx.<region>.compute.internal
之类的东西。而 aws kubernetes 需要通过这个 internal dns hostname 去定位 node 所以需要将 hostname 更改成这个。
先前可以通过 `--hostname-override`` 参数覆盖默认的 aws hostname,但是最近似乎不行了,不如直接修改 hostname 一劳永逸。
curl http://169.254.169.254/latest/meta-data/local-hostname > /etc/hostname
然后重启机器使得更新起效。
如果一开始配置坏了需要重新配置那一定要 kubeadm reset 哦:
kubeadm reset
ifconfig cni0 down
ip link delete cni0
ifconfig flannel.1 down
ip link delete flannel.1
rm -rf /var/lib/cni/
因为我自己安装的 flannel 其他的要看情况修改哦。