内网离线安装docker并配置使用nexus为docker私服
阅读原文时间:2023年09月29日阅读:1

背景

本文简单记录下最近在内网服务器离线安装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包都拿到手,再拷贝到这边来装。

yum remove方式卸载失败

我是采用如下方式(--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 history这个命令,可以将你过往的yum历史操作记录找出来:

我这边不知道为啥,只找到两年前的,我查了网上,好像说默认只能看到最近的20个历史事务。

https://users.fedoraproject.narkive.com/bkvqvTY0/how-to-make-yum-history-show-more-than-the-last-20-transactions

当然了,我们还可以查询某个包相关的事务:

[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://unix.stackexchange.com/questions/303754/how-to-remove-all-installed-dependent-packages-while-removing-a-package-in-cento

https://blog.csdn.net/mighty13/article/details/122412447

重新执行,获取全部rpm

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

https://sf.163.com/

最终注册了个用户。

后面在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次的,结果第二天去了,发现还是拉不下来镜像。

后面就是在网上溜达,看看有没有类似情况的,发现一篇公众号里提到这些事。

Docker 镜像国内加速的几种方法,推荐收藏!

说有个仓库在实时监测这些国内源的情况:

https://github.com/docker-practice/docker-registry-cn-mirror-test/actions

检测脚本(https://github.com/docker-practice/docker-registry-cn-mirror-test/blob/master/.github/workflows/ci.yaml)

执行过程:

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

docker daemon打开debug日志

这些年习惯了抓包解决问题,有时候遇到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

https://docs.docker.com/engine/release-notes/24.0/

https://www.cnblogs.com/xiongzaiqiren/p/16900429.html

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器