master ,这是我的小站,欢迎访问哦~~
本文仅记录docker自建镜像的方法

docker

原因 不可明说,已知docker,npn,pip 均在间接性抽风,所以自建,本文仅记录自建docker镜像的方法

1、利用国外vps自建

介绍

由于Cloudflare在中国大陆的互联性并不是非常理想,所以在有中国优化线路的服务器上搭建一个加速服务可能对大多数人来说才是最优解。本文介绍reigistry方式

项目地址

https://github.com/bboysoulcn/registry-mirror

docker教程

  1. 进入docker目录
    • 如果你想要启动所有的镜像仓库直接执行 docker-compose up -d
    • 但是你想要单独代理某一个仓库就直接进入那个文件夹
    • cd dockerhub
    • docker-compose up -d

k8s教程

都在用k8s了,还想要教程?

注意

大家可以看下配置文件
默认168h小时之后会清理缓存,也就是你拉取的镜像缓存

2、利用利用Cloudflare Worker搭建

  1. 前提条件:需要准备一个域名和一个 Cloudflare 账号
  2. 编写Cloudflare Worker脚本
addEventListener("fetch", (event) => {
  event.passThroughOnException();
  event.respondWith(handleRequest(event.request));
});

const dockerHub = "https://registry-1.docker.io";
const HTML = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="shortcut icon" href="https://xiaowangye.org/assets/img/favicons/favicon.ico">
    <title>Docker 镜像代理使用说明</title>
    <style>
        body {
            font-family: 'Roboto', sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }
        .header {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: #fff;
            padding: 20px 0;
            text-align: center;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }
        .container {
            max-width: 800px;
            margin: 40px auto;
            padding: 20px;
            background-color: #fff;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            border-radius: 10px;
        }
        .content {
            margin-bottom: 20px;
        }
        .footer {
            text-align: center;
            padding: 20px 0;
            background-color: #333;
            color: #fff;
        }
        pre {
            background-color: #272822;
            color: #f8f8f2;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
        }
        code {
            font-family: 'Source Code Pro', monospace;
        }
        a {
            font-weight: bold;
            color: #ffffff;
            text-decoration: none;
        }
        a:hover {
            text-decoration: underline;
        }
        @media (max-width: 600px) {
            .container {
                margin: 20px;
                padding: 15px;
            }
            .header {
                padding: 15px 0;
            }
        }
    </style>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&family=Source+Code+Pro:wght@400;700&display=swap" rel="stylesheet">
</head>
<body>
    <div class="header">
        <h1>Docker 镜像代理使用说明</h1>
    </div>
    <div class="container">
        <div class="content">
          <h3>带镜像仓库地址使用说明</h3>
          <p>1.拉取镜像</p>
          <pre><code># 拉取 redis 官方镜像(不带命名空间)
docker pull /redis

# 拉取 rabbitmq 官方镜像
docker pull /library/rabbitmq

# 拉取 postgresql 非官方镜像
docker pull /bitnami/postgresql</code></pre><p>2.重命名镜像</p>
          <pre><code># 重命名 redis 镜像
docker tag /library/redis redis 

# 重命名 postgresql 镜像
docker tag /bitnami/postgresql bitnami/postgresql</code></pre><h3>镜像源方式使用说明</h3><p>1.添加镜像源</p>
          <pre><code># 添加镜像代理到 Docker 镜像源
sudo tee /etc/docker/daemon.json &lt;&lt; EOF
{
  "registry-mirrors": ["https://"]
}
EOF</code></pre><p>2.拉取镜像</p>
<pre><code># 拉取 redis 官方镜像
docker pull redis

# 拉取 rabbitmq 非官方镜像
docker pull bitnami/rabbitmq

# 拉取 postgresql 官方镜像
docker pull postgresql</code></pre>
        </div>
    </div>
    <div class="footer">
        <p>©2024 <a href="https://xiaowangye.org">xiaowangye.org</a>. All rights reserved. Powered by <a href="https://cloudflare.com">Cloudflare</a>.</p>
    </div>
</body>
</html>
`

const routes = {
  // 替换为你的域名
  "a.b.c": dockerHub,
};

function routeByHosts(host) {
  if (host in routes) {
    return routes[host];
  }
  return "";
}

async function handleRequest(request) {

  const url = new URL(request.url);

  if (url.pathname == "/") {
    return handleHomeRequest(url.host);
  }

  const upstream = routeByHosts(url.hostname);
  if (!upstream) {
    return createNotFoundResponse(routes);
  }

  const isDockerHub = upstream == dockerHub;
  const authorization = request.headers.get("Authorization");
  if (url.pathname == "/v2/") {
    return handleFirstRequest(upstream, authorization, url.hostname);
  }
  // get token
  if (url.pathname == "/v2/auth") {
    return handleAuthRequest(upstream, url, isDockerHub, authorization);
  }
  // redirect for DockerHub library images
  // Example: /v2/busybox/manifests/latest => /v2/library/busybox/manifests/latest
  if (isDockerHub) {
    const pathParts = url.pathname.split("/");
    if (pathParts.length == 5) {
      pathParts.splice(2, 0, "library");
      const redirectUrl = new URL(url);
      redirectUrl.pathname = pathParts.join("/");
      return Response.redirect(redirectUrl.toString(), 301);
    }
  }
  return handlePullRequest(upstream, request);
}

function parseAuthenticate(authenticateStr) {
  // sample: Bearer realm="https://auth.ipv6.docker.com/token",service="registry.docker.io"
  // match strings after =" and before "
  const re = /(?<=\=")(?:\\.|[^"\\])*(?=")/g;
  const matches = authenticateStr.match(re);
  if (matches == null || matches.length < 2) {
    throw new Error(`invalid Www-Authenticate Header: ${authenticateStr}`);
  }
  return {
    realm: matches[0],
    service: matches[1],
  };
}

async function fetchToken(wwwAuthenticate, scope, authorization) {
  const url = new URL(wwwAuthenticate.realm);
  if (wwwAuthenticate.service.length) {
    url.searchParams.set("service", wwwAuthenticate.service);
  }
  if (scope) {
    url.searchParams.set("scope", scope);
  }
  const headers = new Headers();
  if (authorization) {
    headers.set("Authorization", authorization);
  }
  return await fetch(url, { method: "GET", headers: headers });
}

function handleHomeRequest(host) {
  return new Response(HTML.replace(//g, host), {
    status: 200,
    headers: {
      "content-type": "text/html",
    }
  })
}

async function handlePullRequest(upstream, request) {
  const url = new URL(request.url);
  const newUrl = new URL(upstream + url.pathname);
  const newReq = new Request(newUrl, {
    method: request.method,
    headers: request.headers,
    redirect: "follow",
  });
  return await fetch(newReq);
}

async function handleFirstRequest(upstream, authorization, hostname) {
  const newUrl = new URL(upstream + "/v2/");
  const headers = new Headers();
  if (authorization) {
    headers.set("Authorization", authorization);
  }
  // check if need to authenticate
  const resp = await fetch(newUrl.toString(), {
    method: "GET",
    headers: headers,
    redirect: "follow",
  });
  if (resp.status === 401) {
      headers.set(
        "Www-Authenticate",
        `Bearer realm="https://${hostname}/v2/auth",service="cloudflare-docker-proxy"`
      );
    return new Response(JSON.stringify({ message: "Unauthorized" }), {
      status: 401,
      headers: headers,
    });
  } else {
    return resp;
  }
}

async function handleAuthRequest(upstream, url, isDockerHub, authorization) {
  const newUrl = new URL(upstream + "/v2/");
  const resp = await fetch(newUrl.toString(), {
    method: "GET",
    redirect: "follow",
  });
  if (resp.status !== 401) {
    return resp;
  }
  const authenticateStr = resp.headers.get("WWW-Authenticate");
  if (authenticateStr === null) {
    return resp;
  }
  const wwwAuthenticate = parseAuthenticate(authenticateStr);
  let scope = url.searchParams.get("scope");
  // autocomplete repo part into scope for DockerHub library images
  // Example: repository:busybox:pull => repository:library/busybox:pull
  if (scope && isDockerHub) {
    let scopeParts = scope.split(":");
    if (scopeParts.length == 3 && !scopeParts[1].includes("/")) {
      scopeParts[1] = "library/" + scopeParts[1];
      scope = scopeParts.join(":");
    }
  }
  return await fetchToken(wwwAuthenticate, scope, authorization);
}

const createNotFoundResponse = (routes) => new Response(
  JSON.stringify({ routes }),
  {
    status: 404,
    headers: {
      "Content-Type": "application/json",
    },
  }
);
  1. 注意:Cloudflare ip不一定被墙也不一定没墙,自用少用

3、直接配置Docker代理

  1. 环境问题

假设SOCKS 代理地址为 127.0.0.1:1000 ,HTTP 代理地址为 127.0.0.1:2000
首先要确认的是本机是否可以连接到socks和http代理。用以下指令测试节点有效性

# SOCKS 代理
curl -x socks5://127.0.0.1:1000 ip.sb
# HTTP 代理
curl -x 127.0.0.1:2000 ip.sb
#代用户认证的SOCKS代理
curl -x socks5://Username:Password@127.0.0.1:1000 ip.sb

如果返回的是代理的出口IP而不是本机IP,则代表连接成功
2. 配置Docker镜像代理

  • 首先创建 dockerd 相关的 systemd 目录,这种 .d 目录下的配置将覆盖默认配置
sudo mkdir -p /etc/systemd/system/docker.service.d
  • 新建配置文件 http-proxy.conf
sudo vim /etc/systemd/system/docker.service.d/proxy.conf
  • 添加配置
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:2000/"
Environment="HTTPS_PROXY=http://127.0.0.1:2000/"
Environment="NO_PROXY=127.0.0.1,localhost,192.168.*,*.example.com"
# 如果 `NO_PROXY=*`,那么所有请求都将不通过代理服务器
  • 最后重新加载配置文件,重启 Dockerd 才能生效
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker
  1. 配置Docker容器代理

在容器运行阶段,如果需要代理上网,只需要加上环境变量,比如使用 docker-compose 的话,其配置文件里的环境变量,增加下面三部分即可。

    environment:
        - http_proxy="192.168.1.11:2000"
        - https_proxy="192.168.1.11:2000"
        - no_proxy="localhost,127.0.0.1,.example.com"

这个能不能生效,还得看里面运行的服务,会不会主动撷取环境变量了。如果容器默认就使用代理,也可以配置 ~/.docker/config.json

{
 "proxies":
 {
   "default":
   {
     "httpProxy": "http://proxy.example.com:2000",
     "httpsProxy": "http://proxy.example.com:2000",
     "noProxy": "localhost,127.0.0.1,.example.com"
   }
 }
}

4、利用 Github Action 将 DockerHub 镜像转存到阿里云/腾讯云私有仓库

介绍

使用 Github Action 将 DockerHub 镜像转存到阿里云私有仓库,供国内服务器使用,免费易用

项目地址

https://github.com/tech-shrimp/docker_image_pusher

  1. 配置
    • 配置阿里云
      • 登录阿里云容器镜像服务 : https://cr.console.aliyun.com/
      • 启用个人实例,创建一个命名空间(ALIYUN_NAME_SPACE)
      • 访问凭证–>获取环境变量 用户名(ALIYUN_REGISTRY_USER)
      • 密码(ALIYUN_REGISTRY_PASSWORD)
      • 仓库地址(ALIYUN_REGISTRY)
  • Fork 本项目
    • Fork 本项目: https://github.com/tech-shrimp/docker_image_pusher
      点击 Action ,启用 Github Action 功能 配置环境变量
    • 进入 Settings->Secret and variables->Actions->New Repository secret
    • 将上一步的 ALIYUN_NAME_SPACE ,ALIYUN_REGISTRY_USER ,ALIYUN_REGISTRY_PASSWORD ,ALIYUN_REGISTRY 的值配置成环境变量
  1. 使用

打开 images.txt 文件,添加你想要的镜像,可以带 tag ,也可以不用(默认 latest ) 文件提交后自动进入 Github Action 构建

  • 使用镜像
    回到阿里云,镜像仓库,点击任意镜像,可查看镜像状态。(可以改成公开,拉取镜像免登录)
  • 在国内服务器 pull 镜像:
docker pull registry.cn-shanghai.aliyuncs.com/study996/alpine
# 解释
# registry.cn-shanghai.aliyuncs.com 即 ALIYUN_REGISTRY
# study996 即 ALIYUN_NAME_SPACE
# alpine 即 images.txt 里面填的镜像