指尖上的记忆指尖上的记忆
首页
  • 基础
  • Laravel框架
  • Symfony框架
  • 基础
  • Gin框架
  • 基础
  • Spring框架
  • 命令
  • Nginx
  • Ai
  • Deploy
  • Docker
  • K8s
  • Micro
  • RabbitMQ
  • Mysql
  • PostgreSsql
  • Redis
  • MongoDb
  • Html
  • Js
  • 前端
  • 后端
  • Git
  • 知识扫盲
  • Golang
🌟 gitHub
首页
  • 基础
  • Laravel框架
  • Symfony框架
  • 基础
  • Gin框架
  • 基础
  • Spring框架
  • 命令
  • Nginx
  • Ai
  • Deploy
  • Docker
  • K8s
  • Micro
  • RabbitMQ
  • Mysql
  • PostgreSsql
  • Redis
  • MongoDb
  • Html
  • Js
  • 前端
  • 后端
  • Git
  • 知识扫盲
  • Golang
🌟 gitHub

使用docker搭建registry仓库:

1>
$ docker pull docker.1ms.run/registry:2
$ docker image tag docker.1ms.run/registry:2 registry:2
$ docker rmi docker.1ms.run/registry:2

2>
docker run -d \
--name registry \
-p 5000:5000 \
--restart=always \
-v /opt/registry/data:/var/lib/registry \
registry:2

解释:
-d:后台运行容器
--name registry:容器名称
-p 5000:5000:映射本地 5000 端口到容器的 5000 端口
--restart=always:开机自启
-v /opt/registry/data:/var/lib/registry:挂载本地目录到容器内


$ docker ps 和 $ docker container ls 效果一样, docker ps -a 查看所有容器,包括被停止的

3>
验证:
浏览器访问 http://localhost:5000/v2/  或者curl 访问 http://localhost:5000/v2/

返回 {} 表示成功

4>推送和拉取
4.1 先将官网的拉下来,再重新push到本地仓库
docker pull busybox
docker tag busybox localhost:5000/busybox
docker push localhost:5000/busybox

4.2删掉本地的镜像
$ docker rmi localhost:5000/busybox

4.3再从本地仓库拉取
$ docker pull localhost:5000/busybox

结论,可以拉取到本地仓库的镜像


5.配置远程访问
默认情况下,Docker 只允许使用 https 连接到私有仓库。如果你只想在局域网内使用,可以通过配置 Docker 允许 http 访问。

编辑 /etc/docker/daemon.json(如果文件不存在,就创建):
{
"insecure-registries": ["localhost:5000"]
}

然后重启docker:
sudo systemctl restart docker

如果是远程机器访问,将 localhost 替换为你的服务器 IP,例如 192.168.1.100:5000

实际上本地访问不加"insecure-registries": ["localhost:5000"] 也可以,原因如下: 如果你在 本地(localhost) 搭建 Docker Registry,并且 Docker 默认支持推送到 localhost:5000 的 HTTP 端口,那么你可以不配置 "insecure-registries" 也能正常 docker push。

原因分析

  1. Docker 允许 localhost 作为特殊情况
  • localhost 被 Docker 认为是本地地址,因此不会强制 HTTPS 连接。
  • 只要 registry 在 localhost:5000 运行,Docker 允许 http://localhost:5000 进行推送和拉取操作。
  1. "insecure-registries" 主要用于远程访问
  • 如果你在其他机器(如 192.168.1.100:5000)上运行 Registry,默认情况下 Docker 需要 HTTPS 连接。
  • 你必须在 /etc/docker/daemon.json 配置 "insecure-registries": ["192.168.1.100:5000"],否则 docker push 会失败。

什么时候需要 insecure-registries?

  • 本机(localhost) 访问 localhost:5000 → 不需要
  • 局域网(如 192.168.1.100:5000) 访问 → 需要
  • 公网 IP 或域名(如 registry.example.com:5000) 访问 → 需要

如何验证

如果你尝试推送到非 localhost 地址:

docker tag busybox 192.168.1.100:5000/busybox
docker push 192.168.1.100:5000/busybox

你可能会遇到类似的错误:

http: server gave HTTP response to HTTPS client

这表明 Docker 默认需要 HTTPS,你需要在 daemon.json 添加:

{
  "insecure-registries": ["192.168.1.100:5000"]
}

然后重启 Docker:

sudo systemctl restart docker

结论

  • 本地 localhost:5000 访问 registry:2,Docker 默认允许 HTTP,无需额外配置。
  • 远程访问 192.168.1.100:5000 需要 "insecure-registries",否则必须使用 HTTPS。

如果要使用 HTTPS,需要: 申请或自签证书 配置 Docker Registry 使用 HTTPS 在 Docker 客户端信任该证书 需要在 /etc/docker/daemon.json 中配置 registry-mirrors 和 insecure-registries,或者使用反向代理(如 Nginx)加 HTTPS。


要查看Docker Registry(私有仓库)中有哪些镜像,可以使用以下几种方法:

方法 1:使用 curl 直接查询

Docker Registry 提供了一个 REST API,可以用 curl 查询已存储的镜像列表:

curl -X GET http://localhost:5000/v2/_catalog //对应可以直接浏览器访问: http://localhost:5000/v2/_catalog

示例返回:

{
  "repositories": ["busybox", "nginx", "my-app"]
}

这表示你的私有仓库里存储了 busybox、nginx 和 my-app 这三个镜像。

如果你的 Registry 运行在远程服务器(例如 192.168.1.100),可以这样查询:

curl -X GET http://192.168.1.100:5000/v2/_catalog

方法 2:查看某个镜像的所有标签

如果你想查看某个镜像有哪些标签(版本),可以使用:

curl -X GET http://localhost:5000/v2/busybox/tags/list

示例返回:

{
  "name": "busybox",
  "tags": ["latest", "1.35", "1.36"]
}

这表示 busybox 镜像在你的私有仓库中有 latest、1.35 和 1.36 三个版本。


方法 3:使用 Docker CLI

Docker CLI 没有直接的 docker registry ls 命令,但你可以这样做:

docker pull registry:2
docker run --rm registry:2 bin/registry garbage-collect /etc/docker/registry/config.yml

(不推荐,通常 curl 方法更简单)


方法 4:通过 UI 浏览(可选)

如果你希望用 Web 界面来管理 Registry,可以使用 portus 或 docker-registry-ui:

docker run -d -p 8080:80 --name registry-ui \
  -e REGISTRY_URL=http://localhost:5000 \
  -e DELETE_IMAGES=true \
  joxit/docker-registry-ui:latest

然后在浏览器访问:

http://localhost:8080

它会列出所有镜像,并提供管理功能。


总结

  • 最简单的方法:用 curl http://localhost:5000/v2/_catalog
  • 查看具体镜像的版本:curl http://localhost:5000/v2/busybox/tags/list
  • 想用 UI 管理:用 docker-registry-ui 或 portus

为docker私有仓库配置账号和密码:

1>生成用户名和密码(使用 htpasswd 命令创建认证文件)
$ sudo apt install apache2-utils -y   # 安装 htpasswd(如果未安装)
$ sudo mkdir -p /opt/registry/auth         # 存放认证文件
$ sudo htpasswd -B -c /opt/registry/auth/htpasswd myuser
New password:
Re-type new password:
Adding password for user myuser

这会创建 /opt/registry/auth/htpasswd 文件,其中 myuser 是用户名,你可以换成自己的用户名。

2>停止和删除容器,可以先通过 docker ps -a 查看所有容器(包括运行的和停止的)
$ docker stop registry
$ docker rm registry

3>然后重新运行 Registry,增加 -e 环境变量指定认证文件:
docker run -d \
--restart=always \
--name registry \
-p 5000:5000 \
-v /opt/registry/data:/var/lib/registry \
-v /opt/registry/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2

4>验证
再次执行之前的命令,推送到本地仓库:
$ docker push localhost:5000/busybox
Using default tag: latest
The push refers to repository [localhost:5000/busybox]
66140dc7271c: Preparing
no basic auth credentials

会发现没有授权,执行如下命令:
$ docker login localhost:5000
Username: myuser
Password:
WARNING! Your password will be stored unencrypted in /home/guoshipeng/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded


再次执行:
$ docker push localhost:5000/busybox
Using default tag: latest
The push refers to repository [localhost:5000/busybox]
66140dc7271c: Layer already exists
latest: digest: sha256:359e81f9b2a9be2b4ae628a146e0fab4d5b8ac8a386f4e8181f099d0f354dfc4 size: 527


再次删除本地已有的镜像:
$ docker rmi localhost:5000/busybox:latest
然后从本地仓库拉取:
$ docker pull localhost:5000/busybox
Using default tag: latest
latest: Pulling from busybox
Digest: sha256:359e81f9b2a9be2b4ae628a146e0fab4d5b8ac8a386f4e8181f099d0f354dfc4
Status: Downloaded newer image for localhost:5000/busybox:latest
localhost:5000/busybox:latest

完美运行!

新增用户: htpasswd /opt/registry/auth/htpasswd newuser

删除用户: sed -i '/^olduser/d' /opt/registry/auth/htpasswd 解释: 这条命令的作用是 删除 /opt/registry/auth/htpasswd 文件中以 olduser 开头的行,即 删除 olduser 这个用户的密码记录。


命令详解

sed -i '/^olduser/d' /opt/registry/auth/htpasswd
部分作用
sed调用 sed 命令(stream editor,流编辑器)
-i直接修改文件(in-place),否则 sed 只会输出修改结果,而不改变原文件
'/^olduser/d'/^olduser/:匹配以 olduser 开头的行
d:删除匹配的行
/opt/registry/auth/htpasswd要修改的目标文件(存储用户名和密码)

示例

假设 htpasswd 文件内容如下:

olduser:$2y$05$abcde12345...
myuser:$2y$05$xyz98765...
admin:$2y$05$pass45678...

执行:

sed -i '/^olduser/d' /opt/registry/auth/htpasswd

之后 htpasswd 文件变为:

myuser:$2y$05$xyz98765...
admin:$2y$05$pass45678...

✅ olduser 这一行被删除了。


删除多个用户

如果想删除多个用户(如 olduser1 和 olduser2),可以使用 -e 选项:

sed -i -e '/^olduser1/d' -e '/^olduser2/d' /opt/registry/auth/htpasswd

或者用 |(正则表达式的 OR 运算符):

sed -i '/^olduser1\|^olduser2/d' /opt/registry/auth/htpasswd

如何验证删除是否成功?

可以用 cat 或 grep 检查:

cat /opt/registry/auth/htpasswd

或者:

grep 'olduser' /opt/registry/auth/htpasswd

如果 grep 没有输出,说明 olduser 已成功删除。


总结

  • 删除 htpasswd 文件中 olduser 这一行:
    sed -i '/^olduser/d' /opt/registry/auth/htpasswd
    
  • 匹配 htpasswd 文件中多个用户,并删除:
    sed -i '/^olduser1\|^olduser2/d' /opt/registry/auth/htpasswd
    
  • 安全检查,确认用户已删除:
    grep 'olduser' /opt/registry/auth/htpasswd
    

这样,你就可以管理 Docker Registry 的用户访问权限了!

加了用户名和密码之后,上面的查看接口,如: http://localhost:5000/v2/_catalog 访问的时候,就需要输入用户名和秘密


在项目中的gitlab-ci.yml测试这个仓库

运行之后报:
Running with gitlab-runner 17.8.3 (690ce25c)
on a runner for local gitlab t1_UNMMA, system ID: r_iTJKxTxte9W9
Preparing the "shell" executor
00:00
Using Shell (bash) executor...
Preparing environment
00:01
Running on 8446a748968a...
Getting source from Git repository
00:02
Fetching changes with git depth set to 20...
Reinitialized existing Git repository in /home/gitlab-runner/builds/t1_UNMMA/0/front/laravel-15/.git/
Checking out 0a2f2a56 as detached HEAD (ref is main)...
Skipping Git submodules setup
Executing "step_script" stage of the job script
00:00
$ echo "Logging into Docker Registry..."
Logging into Docker Registry...
$ docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$REGISTRY"
bash: line 150: docker: command not found
Cleaning up project directory and file based variables
00:00
ERROR: Job failed: exit status 1


但是之前安装docker-runner的时候,已经挂载了宿主机的docker(参考前面的gitlab-runner搭建),如下可以说明:
# ls -l /var/run/docker.sock
srw-rw---- 1 root gitlab-runner 0 Feb 13  2025 /var/run/docker.sock

这里只是缺少了docker-ci(docker客户端)

# docker exec -it gitlab-runner bash
# docker -v
bash: docker: command not found

//安装docker-cli
# apt update && apt install -y docker.io
...
...

//查看,有了
# docker --version
Docker version 26.1.3, build 26.1.3-0ubuntu1~20.04.1


//继续在gitlab下重试之前的job

Search visible log output
Running with gitlab-runner 17.8.3 (690ce25c)
on a runner for local gitlab t1_UNMMA, system ID: r_iTJKxTxte9W9
Preparing the "shell" executor
00:00
Using Shell (bash) executor...
Preparing environment
00:00
Running on 8446a748968a...
Getting source from Git repository
00:01
Fetching changes with git depth set to 20...
Reinitialized existing Git repository in /home/gitlab-runner/builds/t1_UNMMA/0/front/laravel-15/.git/
Checking out 44958810 as detached HEAD (ref is main)...
Skipping Git submodules setup
Executing "step_script" stage of the job script
00:00
$ echo "Logging into Docker Registry..."
Logging into Docker Registry...
$ export PATH="/usr/bin:$PATH"
$ docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$REGISTRY"
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/gitlab-runner/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ docker build -t "$REGISTRY/$IMAGE_NAME:$CI_COMMIT_REF_NAME" .
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /home/gitlab-runner/builds/t1_UNMMA/0/front/laravel-15/Dockerfile: no such file or directory
Cleaning up project directory and file based variables
00:00
ERROR: Job failed: exit status 1

可以知道gitlab-runner下docker已经登陆成功了,现在的问题是项目没有定义Dockerfile.

现在在已有的目录下初始化一个nuxt3项目,之前的项目不完整,只是随便写了一些东西,没有Dockerfile这些

官方命令:
npx nuxi@latest init <project-name>

由于我的项目已经存在,所以这里直接
npx nuxi@latest init
就可以在当前项目下创建了,会有如下提示:
The directory `/home/guoshipeng/Documents/code/laravel-15` already exists. What would you like to do?
直接 override its contents 就可以了,之前的内容还可以保留

在本地的nuxt3项目的Dockerfile下,需要node镜像,使用如下方法下载
$ docker pull docker.1ms.run/node:20.17.0-alpine
$ docker image tag docker.1ms.run/node:20.17.0-alpine node:20.17.0-alpine
$ docker rmi docker.1ms.run/node:20.17.0-alpine


基于docker + gitlab + gitlab-runner + nginx-proxy + nuxt3 部署项目, 总结如下:

使用如下方式搭建gitlab-runner
docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest
现在gitlab-runner容器里的docker 服务和宿主机上docker的服的相同,那么在gitlab-runner 执行gitlab-ci中的脚本的时候,比如执行 docker  run 相关的命令的时候,就相当于在宿主机上执行docker相关的命令一样。
原因:
由于在运行 gitlab-runner 容器时挂载了 /var/run/docker.sock,容器内的 Docker CLI 实际上是在直接与宿主机上的 Docker Daemon 交互。这意味着:
任何在 gitlab-runner 容器中执行的 docker 命令(例如 docker run、docker build 等),都会直接作用于宿主机的 Docker,而不是 gitlab-runner 容器本身。
运行的容器是由宿主机的 Docker 管理的,而不是 gitlab-runner 容器内部的独立 Docker 进程。
这也意味着 gitlab-ci.yml 中的 docker 相关命令,都会像在宿主机上执行一样起作用。

这样做的好处是可以让 GitLab Runner 直接管理宿主机的 Docker 资源,而不需要在 gitlab-runner 容器内再运行一个 Docker 进程(即 “Docker in Docker” 方案),避免额外的开销和复杂性。


我发现,在gitlab-runner容器里执行,docker ps, 发现展示的内容和直接在宿主机上执行docker ps 一样。
原因:
由于挂载了宿主机的 Docker 套接字(-v /var/run/docker.sock:/var/run/docker.sock),gitlab-runner 容器内部的 docker CLI 实际上是在直接与 宿主机的 Docker Daemon 交互。因此:
在 gitlab-runner 容器中运行 docker ps,它获取的是 宿主机上运行的所有容器(包括 gitlab-runner 容器本身)。
在宿主机上运行 docker ps,看到的内容和 gitlab-runner 容器内执行 docker ps 的内容完全相同。
这个行为可以验证 gitlab-runner 运行的 CI/CD 任务中 docker 命令 是在宿主机上执行的,而不是在 gitlab-runner 容器的独立环境内执行的。


意味着,可以通过tilab-runner运行gitlab-ci,在宿主机上通过docker部署项目,而不是在gitlab-runner容器里部署项目。
这正是 挂载 /var/run/docker.sock 的关键作用,它使 gitlab-runner 充当一个代理,直接在 宿主机的 Docker 环境 中执行 docker 命令,而不是在 gitlab-runner 容器内部。
这样做的好处:
1.项目部署在宿主机,而不是 gitlab-runner 容器内部

gitlab-runner 只负责触发 CI/CD 任务,不会影响你的部署环境。
可以在 gitlab-ci.yml 里自由使用 docker run、docker compose up 等命令,在宿主机上部署项目。

2.避免 Docker in Docker(DinD)带来的问题

传统的 DinD 方案需要在 gitlab-runner 容器内运行一个独立的 Docker Daemon,可能会导致 权限问题、性能损耗 和 容器网络隔离 的问题。
直接挂载 /var/run/docker.sock,就不需要额外的 Docker Daemon,性能更好,部署更简单。

3.可以管理整个宿主机的 Docker 容器

可以在 GitLab CI 中执行 docker ps、docker stop、docker rm 等命令,直接控制宿主机上的容器。
适用于部署 Web 应用、微服务,或者自动化构建和更新 Docker 容器。


举个例子,假设有如下gitlab-ci.yml:
stages:
  - deploy

deploy:
  stage: deploy
  image: docker:latest  # 使用 Docker 官方镜像
  services:
    - docker:dind       # 这里的 DinD 只是用于 GitLab 兼容性,不会真正运行
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker pull my-image:latest
    - docker stop my-container || true
    - docker rm my-container || true
    - docker run -d --name my-container -p 8080:8080 my-image:latest

这样 gitlab-runner 只是触发命令,实际的 docker run 操作都是在 宿主机 上执行的,而不是 gitlab-runner 容器内部。