Docker 008 自建Registry

Docker 008 自建Registry

registry 是什么?可以做什么?

Registry 是一个无状态高扩展的服务程序,他可以存储并分发镜像。

很多时候使用 docker hub 并不方便,尤其是公司内网无法访问公网或者有不想公开的信息的时候,这个时候我们可以自建 registry。

使用 Registry,我们可以:

  • 严格控制镜像的存储位置
  • 镜像发布管道的全部所有权
  • 将镜像的存储和发布紧密的继承到你的内部开发工作流中

如果要执行以下操作,则可使用registry:

  • 严格控制图像的存储位置
  • 完全拥有您的图像分发管道
  • 将图像存储和分发紧密集成到您的内部开发工作流程中

registry 的分类

Sponsor Registry第三方的registry,客户和Docker社区使用
Mirror Registry 第三方的registry,只让客户使用
Vendor Registry 由发布Docker镜像的供应商提供的registry
Private Registry 通过设有防火墙和额外的安全层的私有实体提供的registry

国内可用的 registry

一般使用 docker hub 会比较慢,幸好的是,国内的一些厂商也提供了registry 服务:

国内的镜像源有

  • docker官方中国区 https://registry.docker-cn.com
  • 网易 http://hub-mirror.c.163.com
  • ustc http://docker.mirrors.ustc.edu.cn
  • 阿里云 http://<你的ID>.mirror.aliyuncs.com

如果想使用国内的源,可做如下配置():

# 指定源后,需要重启 docker
$ vim /etc/docker/daemon.json
 
{
 "registry-mirrors": ["https://registry.docker-cn.com"] # 这里是一个列表,可添加多个
}

关于配置文件

参考https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file

Linux上可配置选项的完整示例

{
	"authorization-plugins": [],
	"data-root": "",
	"dns": [],
	"dns-opts": [],
	"dns-search": [],
	"exec-opts": [],
	"exec-root": "",
	"experimental": false,
	"features": {},
	"storage-driver": "",
	"storage-opts": [],
	"labels": [],
	"live-restore": true,
	"log-driver": "json-file",
	"log-opts": {
		"max-size": "10m",
		"max-file":"5",
		"labels": "somelabel",
		"env": "os,customer"
	},
	"mtu": 0,
	"pidfile": "",
	"cluster-store": "",
	"cluster-store-opts": {},
	"cluster-advertise": "",
	"max-concurrent-downloads": 3,
	"max-concurrent-uploads": 5,
	"default-shm-size": "64M",
	"shutdown-timeout": 15,
	"debug": true,
	"hosts": [],
	"log-level": "",
	"tls": true,
	"tlsverify": true,
	"tlscacert": "",
	"tlscert": "",
	"tlskey": "",
	"swarm-default-advertise-addr": "",
	"api-cors-header": "",
	"selinux-enabled": false,
	"userns-remap": "",
	"group": "",
	"cgroup-parent": "",
	"default-ulimits": {
		"nofile": {
			"Name": "nofile",
			"Hard": 64000,
			"Soft": 64000
		}
	},
	"init": false,
	"init-path": "/usr/libexec/docker-init",
	"ipv6": false,
	"iptables": false,
	"ip-forward": false,
	"ip-masq": false,
	"userland-proxy": false,
	"userland-proxy-path": "/usr/libexec/docker-proxy",
	"ip": "0.0.0.0",
	"bridge": "",
	"bip": "",
	"fixed-cidr": "",
	"fixed-cidr-v6": "",
	"default-gateway": "",
	"default-gateway-v6": "",
	"icc": false,
	"raw-logs": false,
	"allow-nondistributable-artifacts": [],
	"registry-mirrors": [],
	"seccomp-profile": "",
	"insecure-registries": [],
	"no-new-privileges": false,
	"default-runtime": "runc",
	"oom-score-adjust": -500,
	"node-generic-resources": ["NVIDIA-GPU=UUID1", "NVIDIA-GPU=UUID2"],
	"runtimes": {
		"cc-runtime": {
			"path": "/usr/bin/cc-runtime"
		},
		"custom": {
			"path": "/usr/local/bin/my-runc-replacement",
			"runtimeArgs": [
				"--debug"
			]
		}
	},
	"default-address-pools":[
		{"base":"172.80.0.0/16","size":24},
		{"base":"172.90.0.0/16","size":24}
	]
}

Win 下的可配置选项的完整示例:

{
    "authorization-plugins": [],
    "data-root": "",
    "dns": [],
    "dns-opts": [],
    "dns-search": [],
    "exec-opts": [],
    "experimental": false,
    "features":{},
    "storage-driver": "",
    "storage-opts": [],
    "labels": [],
    "log-driver": "",
    "mtu": 0,
    "pidfile": "",
    "cluster-store": "",
    "cluster-advertise": "",
    "max-concurrent-downloads": 3,
    "max-concurrent-uploads": 5,
    "shutdown-timeout": 15,
    "debug": true,
    "hosts": [],
    "log-level": "",
    "tlsverify": true,
    "tlscacert": "",
    "tlscert": "",
    "tlskey": "",
    "swarm-default-advertise-addr": "",
    "group": "",
    "default-ulimits": {},
    "bridge": "",
    "fixed-cidr": "",
    "raw-logs": false,
    "allow-nondistributable-artifacts": [],
    "registry-mirrors": [],
    "insecure-registries": []
}

使用容器部署 registry

从容器运行 registry

从容器安装一个 registry 非常简单:

# 启动一个 regidtry 容器
$ docker run -d -p 5000:5000 --name registry registry:2
# --restart参数可以让容器自动重启
$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
# 自定义端口
$ docker run -d -p 5001:5000 --name registry-test registry:2
# 自定义存储后端
$ docker run -d -p 5000:5000 --restart=always --name registry -v /mnt/registry:/var/lib/registry registry:2

# 从 hub 上拉取一个镜像
$ docker pull ubuntu

# 修改镜像 tag,将 tag 指向自建 registry
docker image tag ubuntu localhost:5000/myfirstimage

# 把镜像推送到自建 registry
docker push localhost:5000/myfirstimage

# 从自建 registry 上拉取镜像
docker pull localhost:5000/myfirstimage

# 停止registry容器并删除所有数据
docker container stop registry && docker container rm -v registry

运行一个可外部访问的 registry

上面部署的 registry 只有本地可访问,用途有限;为了使registry可供外部访问,我们首先应使用 TLS 保护它。

获取证书

这里的示例假定已满足如下条件:

  • 你的 registry 的 URL 是 https://myregistry.domain.com/
  • registry 所在主机的443端口允许被访问
  • 你已经从证书颁发机构获取到了证书
  1. 创建certs 目录,并将从 CA 获取到的 .crt和 .key文件复制到 certs 目录;下面的步骤中假定文件名是domain.crtdomain.key

    $ mkdir -p certs
    
  2. 关闭当前运行的 registry:

    $ docker container stop registry
    
  3. 指定 TLS 证书后,重启 registry;下面的命令将 certs 目录绑定到容器的 /certs 目录上,并设置了环境变量,环境变量告诉容器在哪里可以找到domain.crtdomain.key

    $ docker run -d 
      --restart=always 
      --name registry 
      -v "$(pwd)"/certs:/certs 
      -e REGISTRY_HTTP_ADDR=0.0.0.0:443 
      -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt 
      -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key 
      -p 443:443 
      registry:2
    
  4. Docker客户端现在可以用外部地址拉取或推送镜像到你的 registry:

    $ docker pull ubuntu:16.04
    $ docker tag ubuntu:16.04 myregistry.domain.com/my-ubuntu
    $ docker push myregistry.domain.com/my-ubuntu
    $ docker pull myregistry.domain.com/my-ubuntu
    

使用中间证书

证书颁发机构可能会向你提供中间证书,这时,就必须将证书与中间证书连接起来,可使用如下命令完成连接:

$ cat domain.crt intermediate-certificates.pem > certs/domain.crt

可以使用自签名证书,或者使用不安全的 registry (无 TLS),除非已为自签名证书设置了验证,否则不推荐用于非测试环境。

使用 yum 部署 registry

下面的例子中以centos 为例,centos 版本为7.4.1708:

# 安装
$ yum install docker-registry
# 实际安装的软件包是: docker-distribution
# 我这里安装的是 docker-distribution-2.6.2-2.git48294d9.el7.x86_64

# 查看有哪些文件
$ rpm -ql docker-distribution-2.6.2-2.git48294d9.el7.x86_64
/etc/docker-distribution/registry/config.yml
/usr/bin/registry
/usr/lib/systemd/system/docker-distribution.service
/usr/share/doc/docker-distribution-2.6.2
/usr/share/doc/docker-distribution-2.6.2/AUTHORS
/usr/share/doc/docker-distribution-2.6.2/CONTRIBUTING.md
/usr/share/doc/docker-distribution-2.6.2/LICENSE
/usr/share/doc/docker-distribution-2.6.2/MAINTAINERS
/usr/share/doc/docker-distribution-2.6.2/README.md
/var/lib/registry


可以看到,配置文件为/etc/docker-distribution/registry/config.yml,config.yml的格式为 yaml,

# 默认配置
$ cat /etc/docker-distribution/registry/config.yml
version: 0.1   
log: 
  fields:
    service: registry
storage:
    cache:
        layerinfo: inmemory
    filesystem:
        rootdirectory: /var/lib/registry
http:
    addr: :5000
  • version: 必填项,用于指定配置的版本

  • log :用户配置日志记录系统的行为,日志记录系统会将所有的内容输出到标准输出,通过 log 可以调整输出的格式和颗粒度:

    log:
      accesslog:
        disabled: true
      level: debug
      formatter: text
      fields:
        service: registry
        environment: staging
    
    ParameterRequired描述
    level no 设置日志输出级别. 可用的值有 errorwarninfodebug,默认是 info.
    formatter no 设置日志输出的格式,格式主要影响日志行中键控属性的编码方式,值可以是 textjsonlogstash。默认是 text.
    fields no 字段名和值的映射,会被添加到每个日志行的上下文中,对其他系统中混合日志消息源的识别很有用
  • accesslog:

    accesslog:
      disabled: true
    

    在 log 中,accesslog 记录访问日志记录系统的行为,默认访问日志记录系统会用组合日志格式输出到标准输出,通过将 disable 设置为 true 来禁用访问日志记录

更多内容: https://docs.docker.com/registry/configuration/

配置文件的可配置项

参考 https://docs.docker.com/registry/configuration/

version: 0.1
log:
  accesslog:
    disabled: true
  level: debug
  formatter: text
  fields:
    service: registry
    environment: staging
  hooks:
    - type: mail
      disabled: true
      levels:
        - panic
      options:
        smtp:
          addr: mail.example.com:25
          username: mailuser
          password: password
          insecure: true
        from: sender@example.com
        to:
          - errors@example.com
loglevel: debug # deprecated: use "log"
storage:
  filesystem:
    rootdirectory: /var/lib/registry
    maxthreads: 100
  azure:
    accountname: accountname
    accountkey: base64encodedaccountkey
    container: containername
  gcs:
    bucket: bucketname
    keyfile: /path/to/keyfile
    credentials:
      type: service_account
      project_id: project_id_string
      private_key_id: private_key_id_string
      private_key: private_key_string
      client_email: client@example.com
      client_id: client_id_string
      auth_uri: http://example.com/auth_uri
      token_uri: http://example.com/token_uri
      auth_provider_x509_cert_url: http://example.com/provider_cert_url
      client_x509_cert_url: http://example.com/client_cert_url
    rootdirectory: /gcs/object/name/prefix
    chunksize: 5242880
  s3:
    accesskey: awsaccesskey
    secretkey: awssecretkey
    region: us-west-1
    regionendpoint: http://myobjects.local
    bucket: bucketname
    encrypt: true
    keyid: mykeyid
    secure: true
    v4auth: true
    chunksize: 5242880
    multipartcopychunksize: 33554432
    multipartcopymaxconcurrency: 100
    multipartcopythresholdsize: 33554432
    rootdirectory: /s3/object/name/prefix
  swift:
    username: username
    password: password
    authurl: https://storage.myprovider.com/auth/v1.0 or https://storage.myprovider.com/v2.0 or https://storage.myprovider.com/v3/auth
    tenant: tenantname
    tenantid: tenantid
    domain: domain name for Openstack Identity v3 API
    domainid: domain id for Openstack Identity v3 API
    insecureskipverify: true
    region: fr
    container: containername
    rootdirectory: /swift/object/name/prefix
  oss:
    accesskeyid: accesskeyid
    accesskeysecret: accesskeysecret
    region: OSS region name
    endpoint: optional endpoints
    internal: optional internal endpoint
    bucket: OSS bucket
    encrypt: optional data encryption setting
    secure: optional ssl setting
    chunksize: optional size valye
    rootdirectory: optional root directory
  inmemory:  # This driver takes no parameters
  delete:
    enabled: false
  redirect:
    disable: false
  cache:
    blobdescriptor: redis
  maintenance:
    uploadpurging:
      enabled: true
      age: 168h
      interval: 24h
      dryrun: false
    readonly:
      enabled: false
auth:
  silly:
    realm: silly-realm
    service: silly-service
  token:
    autoredirect: true
    realm: token-realm
    service: token-service
    issuer: registry-token-issuer
    rootcertbundle: /root/certs/bundle
  htpasswd:
    realm: basic-realm
    path: /path/to/htpasswd
middleware:
  registry:
    - name: ARegistryMiddleware
      options:
        foo: bar
  repository:
    - name: ARepositoryMiddleware
      options:
        foo: bar
  storage:
    - name: cloudfront
      options:
        baseurl: https://my.cloudfronted.domain.com/
        privatekey: /path/to/pem
        keypairid: cloudfrontkeypairid
        duration: 3000s
        ipfilteredby: awsregion
        awsregion: us-east-1, use-east-2
        updatefrenquency: 12h
        iprangesurl: https://ip-ranges.amazonaws.com/ip-ranges.json
  storage:
    - name: redirect
      options:
        baseurl: https://example.com/
reporting:
  bugsnag:
    apikey: bugsnagapikey
    releasestage: bugsnagreleasestage
    endpoint: bugsnagendpoint
  newrelic:
    licensekey: newreliclicensekey
    name: newrelicname
    verbose: true
http:
  addr: localhost:5000
  prefix: /my/nested/registry/
  host: https://myregistryaddress.org:5000
  secret: asecretforlocaldevelopment
  relativeurls: false
  draintimeout: 60s
  tls:
    certificate: /path/to/x509/public
    key: /path/to/x509/private
    clientcas:
      - /path/to/ca.pem
      - /path/to/another/ca.pem
    letsencrypt:
      cachefile: /path/to/cache-file
      email: emailused@letsencrypt.com
      hosts: [myregistryaddress.org]
  debug:
    addr: localhost:5001
    prometheus:
      enabled: true
      path: /metrics
  headers:
    X-Content-Type-Options: [nosniff]
  http2:
    disabled: false
notifications:
  events:
    includereferences: true
  endpoints:
    - name: alistener
      disabled: false
      url: https://my.listener.com/event
      headers: <http.Header>
      timeout: 1s
      threshold: 10
      backoff: 1s
      ignoredmediatypes:
        - application/octet-stream
      ignore:
        mediatypes:
           - application/octet-stream
        actions:
           - pull
redis:
  addr: localhost:6379
  password: asecret
  db: 0
  dialtimeout: 10ms
  readtimeout: 10ms
  writetimeout: 10ms
  pool:
    maxidle: 16
    maxactive: 64
    idletimeout: 300s
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
  file:
    - file: /path/to/checked/file
      interval: 10s
  http:
    - uri: http://server.to.check/must/return/200
      headers:
        Authorization: [Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==]
      statuscode: 200
      timeout: 3s
      interval: 10s
      threshold: 3
  tcp:
    - addr: redis-server.domain.com:6379
      timeout: 3s
      interval: 10s
      threshold: 3
proxy:
  remoteurl: https://registry-1.docker.io
  username: [username]
  password: [password]
compatibility:
  schema1:
    signingkeyfile: /etc/registry/key.json
    enabled: true
validation:
  manifests:
    urls:
      allow:
        - ^https?://([^/]+.)*example.com/
      deny:
        - ^https?://www.example.com/
原文地址:https://www.cnblogs.com/resn/p/12553094.html