本文简单记录下最近在内网服务器离线安装docker及配置nexus作为docker私服,踩的一些坑。docker和k8s这块技术我跟得不是很紧,18年的时候用过一阵docker,后来发现它并不能解决当时我们遇到的问题,后来就没用了,再一个就是,在宿主机上啥命令都有,也太爽了,反观docker里面啥命令都没有,痛苦,所以没啥必要的话,我一般比较少docker部署。
现在docker,k8s这块已经是事实上标准了,我们工作里也在筹备上云的事情,这块技术也得跟上了。最近工作正好需要选型一个内网搭建的文档中心,知识库那种,可以拿来存各种markdown的文档,看了下网上,各种技术太多了,这次干脆就用docker部署,快速试错。
只是,刚在内网搭个docker,都一堆问题。
开发环境的服务器,全都没有外网,除非提申请给网工,比如,nexus maven私服服务器(ip:1.1.1.1),要访问阿里的maven私服(maven.aliyun.com),那么,提申请就是1.1.1.1访问maven.aliyun.com的80/443端口。
另外,开发环境服务器也是访问不了办公电脑的网段的。
这些网络管控其实也很正常,只是搞工作有点麻烦。
先是在开发服务器A上准备安装docker,但也没办法使用yum安装,需要配置docker官方的yum源:
https://docs.docker.com/engine/install/centos/
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://download.docker.com/linux/centos/$releasever/$basearch/stable
enabled=1
然后里面都是去https://download.docker.com
下载,我又没网络,内网yum源的docker版本又比较旧,看来只能rpm安装了。
然后我就去找rpm,在下面这个网址,下了6,7个rpm:
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/
然后安装:
[root@monitor upload]# rpm -ivh *.rpm
warning: docker-ce-24.0.6-1.el7.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 621e9f35: NOKEY
error: Failed dependencies:
container-selinux >= 2:2.74 is needed by docker-ce-3:24.0.6-1.el7.x86_64
containerd.io >= 1.6.4 is needed by docker-ce-3:24.0.6-1.el7.x86_64
docker-ce-rootless-extras is needed by docker-ce-3:24.0.6-1.el7.x86_64
libcgroup is needed by docker-ce-3:24.0.6-1.el7.x86_64
libseccomp >= 2.3 is needed by docker-ce-3:24.0.6-1.el7.x86_64
docker-buildx-plugin is needed by docker-ce-cli-1:24.0.6-1.el7.x86_64
docker-compose-plugin is needed by docker-ce-cli-1:24.0.6-1.el7.x86_64
我服了,怎么还依赖这么多rpm,这些rpm,在上面网址里还没有,看来这条路太累了,换个方式。
找一台能任意上外网的机器(比如本地虚拟机、个人的云服务器等),用yum的方式,把所有rpm包都拿到手,再拷贝到这边来装。
我是采用如下方式(--downloadonly),以获取tcpdump的rpm为例:
yum install --downloadonly --downloaddir=/root/download tcpdump
执行完成后,就在/root/download拿到了tcpdump的依赖包:
[root@strategy-stg-app-2 download]# ll
total 564
-rw-r--r-- 1 root root 141376 Jun 21 15:45 libpcap-1.5.3-11.el7.x86_64.rpm
-rw-r--r-- 1 root root 431300 Jun 21 15:45 tcpdump-4.9.2-3.el7.x86_64.rpm
行吧,我就把docker那几个包给卸载了,然后继续用上面的方式:
yum remove docker-ce docker-ce-cli ...
然后再安装:
yum install --downloadonly --downloaddir=/root/mypackage/ docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
执行完了去看,发现下载目录下也只有docker相关的几个包,docker依赖的包的rpm是一个没有。
看来,是我卸载的时候,卸的不干净,没把docker那些依赖给卸载掉。
yum history这个命令,可以将你过往的yum历史操作记录找出来:
我这边不知道为啥,只找到两年前的,我查了网上,好像说默认只能看到最近的20个历史事务。
当然了,我们还可以查询某个包相关的事务:
[root@VM-0-6-centos ~]# yum history info docker-ce
Transaction ID : 46
Begin time : Mon Nov 23 10:01:31 2020
End time : 10:01:56 2020 (25 seconds)
User : root <root>
Return-Code : Success
Command Line : install -y docker-ce-19.03.9-3.el7 docker-ce-cli-19.03.9-3.el7 containerd.io
Transaction performed with:
Installed rpm-4.11.3-43.el7.x86_64 @os
Installed yum-3.4.3-167.el7.centos.noarch @os
Installed yum-plugin-fastestmirror-1.1.31-54.el7_8.noarch @updates
Packages Altered:
Dep-Install audit-libs-python-2.8.5-4.el7.x86_64 @os
Dep-Install checkpolicy-2.5-8.el7.x86_64 @os
Dep-Install container-selinux-2:2.119.2-1.911c772.el7_8.noarch @extras
Install containerd.io-1.3.7-3.1.el7.x86_64 @docker-ce-stable
Install docker-ce-3:19.03.9-3.el7.x86_64 @docker-ce-stable
Install docker-ce-cli-1:19.03.9-3.el7.x86_64 @docker-ce-stable
Dep-Install libcgroup-0.41-21.el7.x86_64 @os
Dep-Install libsemanage-python-2.5-14.el7.x86_64 @os
Dep-Install policycoreutils-python-2.5-34.el7.x86_64 @os
Dep-Install python-IPy-0.75-6.el7.noarch @os
Dep-Install setools-libs-3.3.8-4.el7.x86_64 @os
Scriptlet output:
1 setsebool: SELinux is disabled.
这里可以看到时间是2020年,确实就是那时候安装的了,然后可以看到,很多依赖也一起安装了。
此时,我们可以回退这整个事务:
从上面的Transaction ID : 46,拿到事务id,46,然后回退:
yum history undo 46
此时,可以卸载全部的依赖包。当然,这个undo操作执行完成后,也变成了一个事务,也可以回退的。
参考:
https://www.tecmint.com/view-yum-history-to-find-packages-info/
https://blog.csdn.net/mighty13/article/details/122412447
yum install --downloadonly --downloaddir=/root/mypackage/ docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
此时,再把rpm拷贝到目标服务器上,rpm -ivh *.rpm就可以安装完成了。
docker安装完成后,启动:
systemctl start docker
拉取:
docker run hello-world
没外网,自然是报错,所以还要配置私服。我们内网有一个之前其他组搭的nexus,里面好像有docker仓库,看看能不能用吧。
我们nexus上(10.0.218.28),一共2个docker 仓库(一个host类型,存放公司内部镜像,一个proxy类型,连接了https://hub-mirror.c.163.com作为镜像源),最后又搞了一个group类型,聚合了上面两个仓库,对外就用这个group类型就可以,其connector地址为:
所以,在docker这边,只需要修改为如下:
[root@monitor upload]# vim /etc/docker/daemon.json(如没有可新建)
{
"registry-mirrors": ["http://10.0.218.28:8083"],
"insecure-registries": ["http://10.0.218.28:8083"]
}
就算是可以使用该私服了。
接下来就是拉取,听说wordpress这个很多拿来做网站,模版很多,我就拉取试试:
[root@monitor upload]# docker pull wordpress
Using default tag: latest
latest: Pulling from library/wordpress
Get "https://registry-1.docker.io/v2/": dial tcp: lookup registry-1.docker.io on [::1]:53: dial udp [::1]:53: connect: no route to host
网上查了下,乱七八糟的,后面跟着其中一个,配了下dns:
[root@monitor upload]# vim /etc/resolv.conf
然后,这次换了个错误:
[root@monitor upload]# docker pull wordpress
Using default tag: latest
latest: Pulling from library/wordpress
Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
这个错我真是花了不少时间,因为我认为我私服都配好了,为啥还会报这种问题(看起来还是去docker官方拉取),肯定是哪里配置没搞对吧。
当时没有想到好办法,https的,抓包也不好抓;strace跟踪了docker daemon进程,也没看到啥东西。
上网看了会,说,要好像pull时候要单独指定私服仓库地址:
[root@monitor ~]# docker pull 10.0.218.28:8083/wordpress
Using default tag: latest
latest: Pulling from wordpress
manifest for 10.0.218.28:8083/wordpress:latest not found: manifest unknown: manifest unknown
嗯,这次的报错不一样了,什么manifest unknown
。
这次试着tcpdump抓了下和私服之间的网络包:
tcpdump -i any tcp port 8083 -w wordpress.pcap
简单分析了下,一共有几个http请求:
GET /v2/ HTTP/1.1
Host: 10.0.218.28:8083
响应:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="http://10.0.218.28:8083/v2/token",service="http://10.0.218.28:8083/v2/token"
{"errors":[{"code":"UNAUTHORIZED","message":"access to the requested resource is not authorized","detail":null}]}
意思是 需要认证。
获取token
GET /v2/token?account=admin&scope=repository%3Awordpress%3Apull&service=http%3A%2F%2F10.0.218.28%3A8083%2Fv2%2Ftoken HTTP/1.1
Host: 10.0.218.28:8083
返回:
HTTP/1.1 200 OK
{"token":"DockerToken.c1a93413-7ade-389f-9231-4a153f644b74"}
获取wordpress镜像的元数据标识
HEAD /v2/wordpress/manifests/latest HTTP/1.1
Host: 10.0.218.28:8083
HTTP/1.1 200 OK
Docker-Content-Digest: sha256:a078d12a76827322cf95c1e3ae470d30bd518af6e0bdb42f4f49919b2b3ba74b
我是第一次实际看到head类型的请求,返回的header里有一个sha256开头的字符串,下面要用
获取元数据
GET /v2/wordpress/manifests/sha256:a078d12a76827322cf95c1e3ae470d30bd518af6e0bdb42f4f49919b2b3ba74b HTTP/1.1
Host: 10.0.218.28:8083
返回:
HTTP/1.1 200 OK
body为json,里面是元数据
根据架构对应的digest串,获取具体镜像
GET /v2/wordpress/manifests/sha256:b4aabd2efdd7cf033b1f3b883c404ce2a260a27d83294f3a76c8e14b201572e4 HTTP/1.1
Host: 10.0.218.28:8083
HTTP/1.1 404 Not Found
body:
{
"errors": [
{
"code": "MANIFEST_UNKNOWN",
"message": "manifest unknown",
"detail": [
{
"Name": "wordpress"
},
{
"Revision": "sha256:b4aabd2efdd7cf033b1f3b883c404ce2a260a27d83294f3a76c8e14b201572e4"
}
]
}
]
}
最后报的这个错,我就真的不是理解了。
因为是通过nexus访问163那边,前面折腾了半天,后面想起来去nexus看下日志:
2023-09-29 16:34:36,211+0800 WARN [qtp1782934700-19476] admin org.sonatype.nexus.repository.docker.internal.V2Handlers - Is the remote url a valid docker endpoint? Remote host https://hub-mirror.c.163.com/ with path /v2/library/wordpress/manifests/sha256:b4aabd2efdd7cf033b1f3b883c404ce2a260a27d83294f3a76c8e14b201572e4 did not return the expected response. Error message: manifest unknown
意思是感觉163那边返回的有问题。
我就拿日志里这个地址去请求:
意思是被限流了,还说,要提升限额,请访问docker官网的xx网站。
因为上面那个报错信息,我怀疑是我这边请求太频繁了,网上查了下,说是docker从2020年开始限制匿名用户拉取频率为每6个小时分别限制为100,登录的用户为200个。
https://blog.csdn.net/llg___/article/details/127230106
方法嘛,看起来,要么是换个源,要么是docker login,提升到200个。
我就想着,内网nexus服务器只开了到163这个源的网络,开网又麻烦,还是先搞个登录吧,解决目前的问题。
登录就登录,我拿出了docker hub网站的用户名密码,然后docker login,发现他么登不进去啊。
又以为是nexus私服的啥问题。后面就下班了,下班路上看了会docker login这块,思路清晰了一点,决定回家后,先去看看163源官网,看看有没有接口文档,看看这个报错要怎么弄(毕竟是他们报的错)。
后面继续开整,网上找163镜像源的官网都找半天,最终发现是这个:
https://sf.163.com/help/documents/15587821142962176
最终注册了个用户。
后面在nexus服务器上,试着docker login登录网易私服,没想到还登上了,用的刚在网易注册的用户名和密码。
docker login hub-mirror.c.163.com:443
此时,我才反应过来,原来登录不是传docker hub的密码,而是传私服的密码,艹,我还以为它们只是个代理呢,帮忙转发密码过去(现在想想也确实不对,密码一般不会转发,但也说不准啊)
行吧,看来我登私服的话,得传私服的用户名密码了:
docker login 10.0.218.28:8083 -u admin -p xxxxxx
还真是这样。
后来我就想,我现在是通过nexus服务器去163拉取,163说我们过于频繁,那我通过nexus登录163不就行了吗。
后面在网上找了半天nexus的文档,也没发现有这个功能。
哎,看来靠登录来解决163限流的办法,是走不下去了。
后面想着,不是限流吗,至少6小时内还是能拉取100次的,结果第二天去了,发现还是拉不下来镜像。
后面就是在网上溜达,看看有没有类似情况的,发现一篇公众号里提到这些事。
说有个仓库在实时监测这些国内源的情况:
https://github.com/docker-practice/docker-registry-cn-mirror-test/actions
执行过程:
https://github.com/docker-practice/docker-registry-cn-mirror-test/actions/runs/6333166370
我看到检测结果是,163已经挂了,我看了执行日志,163这边的报错也是一模一样。
哎,原来是源头的问题。
另外,发现这个仓库里有些资料不错:
https://github.com/yeasy/docker_practice/blob/master/install/mirror.md
这些年习惯了抓包解决问题,有时候遇到https就没辙(手机端https还能靠代理来搞搞,服务器端这个暂时没研究)
手里有了锤子,看哪里都是钉子,后面反应过来,https的话看日志应该也不错。
将systemctl安装的docker停掉,用下面的方法启动:
/usr/bin/dockerd -l debug
这个是前台启动,仅限自己掌控的docker这么操作。
systemctl stop docker
vim /etc/docker/daemon.json
{
"registry-mirrors": ["http://10.0.218.28:8083"],
"insecure-registries": ["http://10.0.218.28:8083"],
"debug": true
}
systemctl start docker
增加debug:true即可。
然后docker info |grep debug 可以查看是否生效。
一般在tailf /var/log/messages
或者 :
journalctl -u docker
docker pull 10.0.218.28:8083/wordpress
时,dockerd的日志大概如下:
Sep 29 16:33:13 monitor dockerd: time="2023-09-29T16:33:13.348868678+08:00" level=debug msg="Fetching manifest from remote" digest="sha256:a078d12a76827322cf95c1e3ae470d30bd518af6e0bdb42f4f49919b2b3ba74b" error="<nil>" remote="10.0.218.28:8083/wordpress:latest"
Sep 29 16:33:13 monitor dockerd: time="2023-09-29T16:33:13.359405144+08:00" level=error msg="Not continuing with pull after error: manifest unknown: manifest unknown"
虽然也不怎么详细,也能多点信息吧。
另外,也可以看下nexus的日志:
lsof -p 38134(nexus pid)|grep log
找到了日志位置:
/usr/local/nexus/sonatype-work/nexus3/log/nexus.log
nexus的日志在协助甩锅到163那边,也发挥了巨大作用。
我不知道大家有没有遇到这么多问题,反正我这边感觉问题层出不穷的,don't know why.
https://docs.docker.com/config/daemon/
https://platform9.com/kb/kubernetes/enable-debug-logging-for-docker-daemon