Giter Site home page Giter Site logo

xelalexv / dregsy Goto Github PK

View Code? Open in Web Editor NEW
247.0 9.0 52.0 390 KB

Keep container registries in sync

Home Page: https://buymeacoffee.com/xelalex

License: Apache License 2.0

Go 85.67% Dockerfile 4.04% Makefile 6.45% Shell 3.84%
docker k8s sync-tasks aws-ecr registries skopeo

dregsy's Introduction

dregsy - Container Registry Sync

Synopsis

dregsy lets you sync container images between registries, public or private. Several sync tasks can be defined, as one-off or periodic tasks (see Configuration section). An image is synced by using a sync relay. Currently, this can be either Skopeo or a local Docker daemon. When using the latter, the image is first pulled from the source, then tagged for the destination, and finally pushed there. Skopeo in contrast, can directly transfer an image from source to destination, which makes it the preferred choice.

Configuration

Sync tasks are defined in a YAML config file:

# relay type, either 'skopeo' or 'docker'
relay: skopeo

# whether to watch this config file and restart on change, defaults to false
watch: true

# relay config sections
skopeo:
  # path to the skopeo binary; defaults to 'skopeo', in which case it needs to
  # be in PATH
  binary: skopeo
  # directory under which to look for client certs & keys, as well as CA certs
  # (see note below)
  certs-dir: /etc/skopeo/certs.d

docker:
  # Docker host to use as the relay
  dockerhost: unix:///var/run/docker.sock
  # Docker API version to use, defaults to 1.41
  api-version: 1.41

# settings for image matching (see below)
lister:
  # maximum number of repositories to list, set to -1 for no limit, defaults to 100
  maxItems: 100
  # for how long a repository list will be re-used before retrieving again;
  # specify as a Go duration value ('s', 'm', or 'h'), set to -1 for not caching,
  # defaults to 1h
  cacheDuration: 1h

# list of sync tasks
tasks:

  - name: task1 # required

    # interval in seconds at which the task should be run; when omitted,
    # the task is only run once at start-up
    interval: 60

    # determines whether for this task, more verbose output should be
    # produced; defaults to false when omitted
    verbose: true

    # 'source' and 'target' are both required and describe the source and
    # target registries for this task:
    #  - 'registry' points to the server; required
    #  - 'auth' contains the base64 encoded credentials for the registry
    #    in JSON form {"username": "...", "password": "..."}
    #  - 'auth-refresh' specifies an interval for automatic retrieval of
    #    credentials; only for AWS ECR (see below)
    #  - 'skip-tls-verify' determines whether to skip TLS verification for the
    #    registry server (only for 'skopeo', see note below); defaults to false
    source:
      registry: source-registry.acme.com
      auth: eyJ1c2VybmFtZSI6ICJhbGV4IiwgInBhc3N3b3JkIjogInNlY3JldCJ9Cg==
    target:
      registry: dest-registry.acme.com
      auth: eyJ1c2VybmFtZSI6ICJhbGV4IiwgInBhc3N3b3JkIjogImFsc29zZWNyZXQifQo=
      skip-tls-verify: true

    # 'mappings' is a list of 'from':'to' pairs that define mappings of image
    # paths in the source registry to paths in the destination:
    #  - 'from' is required, while 'to' can be dropped if the path should remain
    #     the same as 'from'.
    #  - Regular expressions are supported in both fields (read on below for
    #    more details).
    #  - The tags being synced for a mapping can be limited by providing a 'tags'
    #    list. This list may contain semver and regular expressions filters
    #    (see below). When omitted, all image tags are synced.
    #  - With 'platform', the image to sync from a multi-platform source image
    #    can be selected (see below).
    mappings:
      - from: test/image
        to: archive/test/image
        tags: ['0.1.0', '0.1.1']
      - from: test/another-image
        platform: linux/arm64/v8

Caveats

When syncing via a Docker relay, do not use the same Docker daemon for building local images (even better: don't use it for anything else but syncing). There is a risk that the reference to a locally built image clashes with the shorthand notation for a reference to an image on docker.io. E.g. if you built a local image busybox, then this would be indistinguishable from the shorthand busybox pointing to docker.io/library/busybox. One way to avoid this is to use registry.hub.docker.com instead of docker.io in references, which would never get shortened. If you're not syncing from/to docker.io, then all of this is not a concern.

Config File Watch & Restart α feature

By setting watch: true, you can make dregsy watch the config file. If it changes, dregsy will restart. If there is a task currently being synced, dregsy waits for it to complete. The restart is a full restart, so if your config contains one-off tasks, they will be run. If dregsy was started with a task filter via the run option, this filter stays active. If the new config causes any validation errors, dregsy will stop. Note that the config file watch does not work if the file resides on an NFS, SMB, or FUSE file system (see the fsnotify package).

Triggering Restart with SIGHUP

You can also trigger a restart by sending SIGHUP to the dregsy process. This can be useful if you want more control over when a restart should occur, or you cannot use config file watch. The restart behavior is the same as outlined above for config file watch.

Image Matching

The mappings section of a task can employ Go regular expressions for describing what images to sync, and how to change the destination path and name of an image. Details about how this works and examples can be found in this design document. Also keep in mind that regular expressions can be surprising at times, so it would be a good idea to try them out first in a Go playground. You may otherwise potentially sync large numbers of images, clogging your target registry, or running into rate limits. Feedback about this feature is encouraged!

Tag Filtering

The tags list of a task can use semver and regular expression filters, so you can do something like this:

tags:
  - 'semver: >=1.31.0 <1.31.9'
  - 'regex: 1\.26\.[0-9]-(glibc|uclibc|musl)'
  - '1.29.4'
  - 'latest'

This syncs all tags describing versions equal to or larger than 1.31.0, but lower than 1.31.9, via the semver: filter. The regex: filter additionally syncs any 1.26.x image with suffix -glibc, -uclibc, or -musl. Finally, the verbatim tags 1.29.4 and latest are also synced.

Note that the tags of an image need to conform to the semver specification 2.0.0 in order to be considered during filtering. The implementation uses the blang/semver lib. Have a look at their page or the GoDoc for more info on how to write semver filter expressions. Semver filtering handles tags starting with a v prefix. It also tolerates suffixes, for example platform IDs which are often used in tags, as long as the tag starts with a full major.minor.patch semver. Semver filter expressions however must not use a v prefix or any suffix.

Regex filters use standard Go regular expressions. When the first non-whitespace character after regex: is !, the filter will use inverted match. Keep in mind that when a regex contains a backslash, you need to place it inside single quotes to keep the YAML valid.

You can add multiple semver: and regex: filters under tags. Note however that the filters are simply ORed, i.e. a tag is synced if it satisfies at least one of the items under tags, be it semver, regex, or verbatim. So this is not a filter chain. Also, no sanity checks are done on the filters, so care must be taken to avoid competing or contradicting filters that select all or nothing at all.

Tag Set Pruning β feature

Additionally it is possible to prune the resulting tag set with one or more keep: filters. These are regular expressions, identical to regex: filters (including inversion), but they get applied last, independent of where in the list they appear. If a tag in the filtered tag set does not match all of the keep: filters, it is removed from the set. This helps in defining tag filters that would be hard to describe with only semver and regular expressions. Note however that keep: filters do not apply to verbatim tags!

Here's an example for a source registry that attaches OS suffixes to their version tags, such as 2.1.4-buster:

tags:
  - 'latest'
  - 'semver: >=2.0.0'
  - 'keep: .+-(alpine|buster)'

This selects all releases starting with version 2.0.0, but only for the -alpine and -buster suffixes. The latest tag however is still included in the sync.

Limiting the Tag Count α feature

A special keep: directive is keep: latest n. This limits the set of tags to the latest n tags, and is enforced at the very end of tag set pruning, i.e. on the already pruned tag set. The latest tags are determined by sorting the tags as semvers in descending order and picking the first n. Any tags that are not legal semvers are kept, so the reduced set may actually contain more than n items. This allows to include certain verbatim tags such as testing or qa in addition to the latest n releases. However, if there are no legal semver tags in the set at all, the first n tags based on a descending string sort are picked.

Here is an example:

tags:
  - 'glibc-tests'
  - 'semver: >=1.34.0 <=1.36.0'
  - 'keep: latest 5'

This selects all releases from version 1.34.0 through 1.36.0, but limits them to the latest 5. The verbatim tag glibc-tests is always included.

Keep the following in mind when using tag count limits:

  • Since for repositories using both semver and non-semver tags, the latter ones are always kept, use appropriate tag & pruning filters if there are many non-semver tags. This avoids overly large result sets, which could otherwise render tag count limiting useless.

  • For repositories with no semver tags, tag count limiting may not be suitable depending on what kind of tags are present. When sorted in string order, the tags need to represent their temporal order. Where for example arbitrary code names are used, this will not work.

  • If several keep: latest directives are specified in a tags list, the last one is used.

Tags With Digests α feature

Verbatim tags in a tags list may also contain image digests to uniquely identify the requested image. The format for verbatim tags with digests is [tag@]sha256:{digest value}, i.e. the tag name can be dropped. As all verbatim tags, they can be mixed with tag filter expressions (see above). If a digest is present, the behavior is as follows:

  • When pulling from the source, the tag is dropped if present, and only the digest used. This is done to achieve consistent behavior between the Skopeo and Docker relays.

    Background: Skopeo currently does not support both tag and digest in the same image reference and exits with an error. For Docker, the behavior depends on the version: up through version 1.13.1 and starting again with v20.10.20, Docker checks whether tag and digest match and throws an error if they don't. For versions in between, the tag is ignored.

  • When pushing to the target, the name if present is used and the digest dropped. Otherwise the digest is used.

    If there is only a digest, the Docker relay auto-generates a tag of the format dregsy-{digest value}, since Docker does not support pushing by digest-only references. If tags of this format are not desired, specify tags for all digests in your sync config, which would then be used instead.

Here's an example:

tags:
  - 'sha256:1d8a...'
  - '1.36.0-uclibc@sha256:58f1...'

This syncs two distinct versions of an image, according to the given SHA256 sums. For the second digest in the list, tag 1.36.0-uclibc is created in the target repository.

Platform Selection (Multi-Platform Source Images) β feature

When the source image is a multi-platform image, the platform image adequate for the system on which dregsy runs is synced by default. Where this is not applicable, the desired platform can be specified via the platform setting, separately for each mapping. To sync all available platform images, platform: all can be used. Note however that this shorthand is only supported by the Skopeo relay.

To sync a selection of platform images from the same multi-platform source image, several mappings with according platform settings can be defined. However, be careful not to map them into the same destination, i.e. use different to settings. Otherwise, the synced platform images will "overwrite" each other, with only the last image synced being available from the target repository.

Repository Validation & Client Authentication with TLS

When connecting to source and target repository servers, TLS validation is performed to verify the identity of a server. If you're using self-signed certificates for a repo server, or a server's certificate cannot be validated with the CA bundle available on your system, you need to provide the required CA certs. The dregsy container image includes the CA bundle that comes with the Alpine base image. Also, if a repo server requires client authentication, i.e. mutual TLS, you need to provide an appropriate client key & cert pair.

How you do that for Docker is described here. The short version: create a folder under /etc/docker/certs.d with the same name as the repo server's host name, e.g. source-registry.acme.com, and place any required CA certs there as *.crt (mind the extension). Client key & cert pairs go there as well, as *.key and *.cert.

Example:

/etc/docker/certs.d/
    └── source-registry.acme.com
       ├── client.cert
       ├── client.key
       └── ca.crt

When using the skopeo relay, this is essentially the same, except that you specify the root folder with the skopeo setting certs-dir (defaults to /etc/skopeo/certs.d). However, it's important to note the following differences:

  • When a repo server uses a non-standard port, the port number is included in image references when pulling and pushing. For TLS validation, docker will accordingly expect a {registry host name}:{port} folder. For skopeo, this is not the case, i.e. the port number is dropped from the folder name. This was a conscious decision to avoid pain when running dregsy in Kubernetes and mounting certs & keys from secrets: mount paths must not contain :.

  • To skip TLS verification for a particular repo server when using the docker relay, you need to configure the Docker daemon accordingly. With skopeo, you can easily set this in any source or target definition with the skip-tls-verify setting.

AWS ECR (private & public)

If a source (private registry only) or target (private & public) is an AWS ECR registry, you need to retrieve the auth credentials via AWS CLI. They would however only be good for 12 hours, which is ok for one off tasks. For periodic tasks, or to avoid retrieving the credentials manually, you can specify an auth-refresh interval as a Go Duration, e.g. 10h. If set, dregsy will initially and whenever the refresh interval has expired retrieve new access credentials. auth can be omitted when auth-refresh is set. Setting auth-refresh for anything other than an AWS ECR registry will raise an error.

Note however that you either need to set environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY for the AWS account you want to use and a user with sufficient permissions. Or if you're running dregsy on an EC2 instance in your AWS account, the machine should have an appropriate instance profile. An according policy could look like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken",
        "ecr:CreateRepository"
      ],
      "Resource": ["*"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:BatchCheckLayerAvailability",
        "ecr:DescribeRepositories",
        "ecr:PutImage",
        "ecr:InitiateLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:CompleteLayerUpload"
      ],
      "Resource": "arn:aws:ecr:<your_region>:<your_account>:repository/*"
    }
  ]
}

Google Container Registry (GCR) and Google Artifact Registry

If a source or target is a Google Container Registry (GCR) or a Google Artifact Registry for containers, auth may be omitted altogether. In this case either GOOGLE_APPLICATION_CREDENTIALS variable must be set (which is supposed to contain a path to a JSON file with credentials for a GCP service account), or dregsy must be run on a GCE instance with an appropriate service account attached. registry must be either specified as any of the GCR addresses (i.e. gcr.io, us.gcr.io, eu.gcr.io, or asia.gcr.io), or have the suffix -docker.pkg.dev for artifact registry. The from/to mapping must include your GCP project name (i.e. your-project-123/your-image). Note that GOOGLE_APPLICATION_CREDENTIALS, if set, takes precedence even on a GCE instance.

If these mechanisms are not applicable in your use case, you can also authenticate with an OAuth2 token as described in the Artifact Registry Authentication -> Access token documentation. This token will then be used continuously without performing any authentication refreshes. In this case, set the content of auth to the base64 encoded JSON credentials:

{
    "username": "oauth2accesstoken",
    "password": "<oauth2 token as described in the Artifact Registry documentation>"
}

If you want to use GCR or artifact registry as the source for a public image, you can deactivate authentication all together by setting auth to none.

Keeping the Config Dry & Secure

If you need to use the same configuration items in several places, for example when you want to sync the same image mapping from one source registry to several different destinations, you can use YAML anchors & aliases to avoid duplication. For example:

tasks:
- name: one
  source: &source
    registry: source.reg
  target:
    registry: foo
  mappings: &mappings
  - from: library/busybox
    to: base/library/busybox
    tags: ['a', 'b', 'c']
  - ...
- name: two
  source: *source
  target:
    registry: bar
  mappings: *mappings

This sets the anchors source and mappings for the source registry and the desired mapping on their first occurrence, which are then referenced with *source and *mappings wherever else they are needed.

If you want to avoid including secrets such as registry passwords in the config, you can put ${...} style variables in their place, and use for example envsubst (either standard from package repos, or this one for more options) to substitute them during deployment, while secrets are present in the environment.

Usage

dregsy -config={path to config file} [-run={task name regexp}]

If there are any periodic sync tasks defined (see Configuration above), dregsy remains running indefinitely. Otherwise, it will return once all one-off tasks have been processed. With the -run argument you can filter tasks. Only those tasks for which the task name matches the given regular expression will be run. Note that the regular expression performs a line match, so you don't need to place the expression in ^...$ to get an exact match. For example, -run=task-a will only select task-a, but not task-abc.

Logging

Logging behavior can be changed with these environment variables:

variable function values
LOG_LEVEL log level; defaults to info fatal, error, warn, info, debug, trace
LOG_FORMAT log format; gets automatically switched to JSON when dregsy is run without a TTY json to force JSON log format, text to force text output
LOG_FORCE_COLORS force colored log messages when running with a TTY true, false
LOG_METHODS include method names in log messages true, false

Running Natively

Pre-built binaries are provided in the release section of this project. Note however that currently, only the linux_amd64 flavor is tested upon release. All other binaries are untested. Feedback is welcome!

If you run dregsy natively on your system, with relay type docker, the Docker daemon of your system will be used as the relay for all sync tasks, so all synced images will wind up in the Docker storage of that daemon.

Running Inside a Container

You can use the dregsy image on Dockerhub for running dregsy containerized. There are two variants: one is based on Alpine, and suitable when you just want to run dregsy. The other variant is based on Ubuntu. It's somewhat larger, but may be better suited as a base when you want to extend the dregsy image. It's often easier to add things there than on Alpine, e.g. the AWS command line interface.

With each release, three tags get published: {version}-ubuntu, {version}-alpine, and {version}, with the latter two referring to the same image. The same applies for latest. The Skopeo versions contained in the two variants may not always be exactly the same, but should only differ in patch level.

With skopeo relay

The image includes the skopeo binary, so all that's needed is:

docker run --rm -v {path to config file}:/config.yaml xelalex/dregsy

With docker relay

This will still use the local Docker daemon as the relay:

docker run --privileged --rm -v {path to config file}:/config.yaml -v /var/run/docker.sock:/var/run/docker.sock xelalex/dregsy

Running On Kubernetes

When you run a container registry inside your Kubernetes cluster as an image cache, dregsy can come in handy as an automated updater for that cache. The example config below uses the skopeo relay:

relay: skopeo
tasks:
  - name: task1
    interval: 60
    source:
      registry: registry.acme.com
      auth: eyJ1c2VybmFtZSI6ICJhbGV4IiwgInBhc3N3b3JkIjogInNlY3JldCJ9Cg==
    target:
      registry: registry.my-cluster
      auth: eyJ1c2VybmFtZSI6ICJhbGV4IiwgInBhc3N3b3JkIjogImFsc29zZWNyZXQifQo=
    mappings:
      - from: test/image
        to: archive/test/image
      - from: test/another-image

To keep your registry auth tokens in the config file secure, we are creating a Kubernetes Secret instead of a ConfigMap:

kubectl create secret generic dregsy-config --from-file=./config.yaml

In addition, you will most likely want to mount client certs & keys, and CA certs from Kubernetes secrets into the pod for TLS validation to work. (The CA bundle from the official golang image is already included in the dregsy image.)

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: kube-registry-updater
  namespace: kube-system
  labels:
    k8s-app: kube-registry-updater
    kubernetes.io/cluster-service: "true"
spec:
  serviceName: kube-registry-updater
  replicas: 1
  template:
    metadata:
      labels:
        k8s-app: kube-registry-updater
        kubernetes.io/cluster-service: "true"
    spec:
      containers:
      - name: dregsy
        image: xelalex/dregsy
        command: ['dregsy', '-config=/config/config.yaml']
        resources:
          requests:
            cpu: 10m
            memory: 32Mi
        volumeMounts:
        - name: dregsy-config
          mountPath: /config
          readOnly: true
      volumes:
      - name: dregsy-config
        secret:
          secretName: dregsy-config

Development

Building

The Makefile has targets for building the binary and container image, and other stuff. Just run make to get a list of the targets, and info about configuration items. Note that for consistency, building is done inside a Golang build container, so you will need Docker to build. dregsy's Docker image is based on Alpine, and installs Skopeo via apk during the image build.

Testing

Tests are also started via the Makefile. To run the tests, you will need to prepare the following:

  • Configure the Docker daemon: The tests run containerized, but need access to the local Docker daemon for testing the Docker relay. One way is to mount the /var/run/docker.socks socket into the container (the Makefile takes care of that). However, the docker group on the host may not map onto the group of the user inside the testing container. The preferred way is therefore to let the Docker daemon listen on 127.0.0.1:2375. Since the testing container runs with host network, the tests can access this directly. Decide which setup to use and configure the Docker daemon accordingly. Additionally, set it to accept 127.0.0.1:5000 as an insecure registry.

  • An AWS account to test syncing with ECR: Create a technical user in that account. This user should have full ECR permissions, i.e. the AmazonEC2ContainerRegistryFullAccess policy attached, since it will delete the used repo after the tests are done.

  • A Google Cloud account to test syncing with GCR and artifact registry: Create a project with the Container Registry and Artifact Registry APIs enabled. In that project, you need a service account with the roles Cloud Build Service Agent, Storage Object Admin, and Artifact Registry Repository Administrator enabled, since this service account also will need to delete the synced images again after the tests.

The details for above requirements are configured via a .makerc file in the root of this project. Just run make and check the Notes section in the help output. Here's an example:

# Docker config; to use the Unix socket, set to unix:///var/run/docker.sock
DREGSY_TEST_DOCKERHOST = tcp://127.0.0.1:2375

# ECR
DREGSY_TEST_ECR_REGISTRY = {account ID}.dkr.ecr.eu-central-1.amazonaws.com
DREGSY_TEST_ECR_REPO = dregsy/test
AWS_ACCESS_KEY_ID = {key ID}
AWS_SECRET_ACCESS_KEY = {access key}

# GCP
GCP_CREDENTIALS = {full path to access JSON of service account}

# GCR
DREGSY_TEST_GCR_HOST = eu.gcr.io
DREGSY_TEST_GCR_PROJECT = {your project}
DREGSY_TEST_GCR_IMAGE = dregsy/test

# GAR
DREGSY_TEST_GAR_HOST = europe-west3-docker.pkg.dev
DREGSY_TEST_GAR_PROJECT = {your project}
DREGSY_TEST_GAR_IMAGE = dregsy/test

Selecting Test Cases

You can select a particular test case with the -run argument, which you can pass to go test via the TEST_OPTS environment variable. Note that the -run argument is a regular expression. This for example would run only the Skopeo end-to-end tests, with verbose output and skipping the Ubuntu based dregsy image:

VERBOSE=y TEST_UBUNTU=n TEST_OPTS="-run TestE2ESkopeo.*" make tests

dregsy's People

Contributors

fhemberger avatar fitz7 avatar lance0805 avatar nouse avatar renchap avatar rromic avatar sjthespian avatar unix-way avatar weeezes avatar xelalexv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dregsy's Issues

Use GCR without auth?

Hi, I'd like to synch some public repos from GCR. An example being k8s.gcr.io/autoscaling/vpa-admission-controller.

It seems like the current implementation of dregsy requires me to provide project credentials because the registry has gcr.io in the name. This isn't necessary and I would like to avoid it. Is there any way to do this that I am missing?

If not, I'm willing to make a PR to address this. Perhaps the code could proceed without GCR credentials and treat the lack thereof as a warning and not an error?

[feat req/debate] adding support for image digests with the skopeo relay

Hello @ALL, I am currently trying to figure out how to add support for image digests copy/sync in dregsy.

I think this is even simpler to implement than the tags based mapping which supports using regular expression to search through tags. Indeed with image digests, there is no need for search with regular expression, since a digest is unique and uniquely identify one particular image.

Image digest are also more robust than tags in certain situation when there is the need to match a very precise version of an image. And image digest are also used for crypto signature of container images.

What do you think about that? I must say, the dregsy source code is not really well documented. But I think I am starting to understand it a bit. I have several ideas as well.

Description of image digests

An image digest looks like this below: using crane

$ crane digest --platform="linux/amd64" library/busybox:1.29.2
sha256:5e8e0509e829bb8f990249135a36e81a3ecbe94294e7a185cc14616e5fad96bd

skopeo & digests

A skopeo copy command using digest rather than tags looks like this :

skopeo copy --preserve-digests docker://docker.io/registry@sha256:cc6393207bf9d3e032c4d9277834c1695117532c9f7e8c64e7b7adcda3a85f39      docker-archive:./registry-linux-amd64-2.8.1.tar:myreg.net/mypath/registry:2.8.1

Important note: Skopeo (1.10.0) DOES NOT support using tags and digest at the same time.

dregsy configuration with digests

Below is an example of what could be a dregsy-config.yaml file which uses digests

# test/fixtures/config/skopeo-digest-valid.yaml
relay: skopeo

lister:
  maxItems: 50
  cacheDuration: 30m

tasks:
- name: test-skopeo-digest-valid
  interval: 30
  verbose: true
  source:
    registry: registry.hub.docker.com
  target:
    registry: 127.0.0.1:5000
    auth: something
    skip-tls-verify: true
  mappings:
  # Tags based mapping
  #~~~~~~~~~~~~~~~~~
  - from: library/busybox
    to: skopeo/library/busybox
    tags: ['1.29.2', '1.29.3', 'latest']
    platform: linux/arm/v6

  # Digests based mapping
  #~~~~~~~~~~~~~~~~~~~~
  - from: library/busybox
    digests:
    - sha256:5e8e0509e829bb8f990249135a36e81a3ecbe94294e7a185cc14616e5fad96bd
    - sha256:76582bc9c59276ea11459bf5ff4f54fd5b7fd23ff622d80479156108fdd26470
    - sha256:6ba3c395f0a2941114d8dcdf80bedcc7e654252f5870dd94daff9cc3188f3eb2
    to: skopeo/library/busybox

  # Using either the WEB GUI at https://hub.docker.com/_/busybox/tags. Or using
  # the tool crane* to get digests from CLI.
  # *crane : https://github.com/google/go-containerregistry/tree/main/cmd/crane
  #
  # $ crane digest --platform="linux/amd64" library/busybox:1.29.2
  # sha256:5e8e0509e829bb8f990249135a36e81a3ecbe94294e7a185cc14616e5fad96bd
  #
  # $ crane digest --platform="linux/arm/v6" library/busybox:1.29.2
  # sha256:6ba3c395f0a2941114d8dcdf80bedcc7e654252f5870dd94daff9cc3188f3eb2
  #
  # $ crane digest --platform="linux/arm64" library/busybox:1.29.3
  # sha256:76582bc9c59276ea11459bf5ff4f54fd5b7fd23ff622d80479156108fdd26470

It is probably better to differentiate and separate "Tags based mapping" and "Digests based mapping", since skopeo does not support both at the same time.

However it might be possible to have a more compact version where both a tag list and a digest list are part of the same mapping object. The skopeo copy requests are different when they use tags or digest (see above the skopeo example with digest).

Also with digest, you can ignore platform:, since the digest already uniquely identify a precise image.

  mappings:
  # Tags based mapping
  #~~~~~~~~~~~~~~~~~
  - from: library/busybox
    to: skopeo/library/busybox
    tags: ['1.29.2', '1.29.3', 'latest']
    platform: linux/arm/v6
    digests:
    - sha256:5e8e0509e829bb8f990249135a36e81a3ecbe94294e7a185cc14616e5fad96bd
    - sha256:76582bc9c59276ea11459bf5ff4f54fd5b7fd23ff622d80479156108fdd26470
    - sha256:6ba3c395f0a2941114d8dcdf80bedcc7e654252f5870dd94daff9cc3188f3eb2

But it might be overkill to dedicate task to either tag only or digest only.

Tags filtering / skip tags that already exist in the target registry

Hello 👋

I have implemented some minimal logic for tag filtering: https://github.com/yannh/dregsy#tags-filtering , support for wildcards, comparison operators, and exclude tag ranges.

I have also implemented an option called "skipExistingTags" - dregsy will skip tags that already exist in the target registry. Since it might cause issues with tags that are not immutable such as 'latest' it is deactivated by default.

To easily implement both these features, I have removed the docker relay - see #21

Do you see a path to merge this back here? I am happy to work on clean PRs. But I am not sure how to implement this efficiently using the docker relay :/

Thanks! 👍

Allow use of skopeo's `sync` command instead of `copy`

I am using skopeo to sync my registries, but every time it runs it transfers data, even if it has already copied the image in the prior pass. I see the last modified time in the destination registry update on each run. My expectation was that this would work more like rsync -- i.e. only copying data that has changed on each task run.

Even more importantly, I would expect skopeo to only copy layers that have changed. It looks like the way it is running now it will copy layers that already exist on the destination multiple times if they are used by multiple images.

Is there a way, short of editing the tags list in the yaml file after a successful copy, to only have dregsy sync images that don't exist in the destination?

I am using a local build of dregsy built from the master branch in GitHub and skopeo 1.4.1.

Obfuscated config and log output:

relay: skopeo
skopeo:
  binary: skopeo
docker:
  dockerhost: unix:///var/run/docker.sock
  api-version: 1.24
lister:
  maxItems: 100
  cacheDuration: 1h
tasks:
  - name: sync-lab
    interval: 60
    verbose: true
    source:
      registry: registry.xxxxxx.com
      auth: xxxxxxxxxxx
    target:
      registry: registry1.xxxxxx.com
      auth: xxxxxxxxxxx
    mappings:
      - from: regex:sync/alpine
        to: regex:sync/alpine,synctest-$1
❯ LOG_LEVEL=debug _build/bin/dregsy --config shipsync.yml
INFO[0000] dregsy 0.4.1-dirty
DEBU[0000] lister max items set to 100
DEBU[0000] lister cache duration set to 1h0m0s
INFO[0000] skopeo version 1.4.1
INFO[0000] relay ready                                   relay=skopeo
DEBU[0000] task starts ticking                           task=sync-lab
DEBU[0000] sending initial fire                          task=sync-lab
INFO[0000] waiting for next sync task...
INFO[0000] syncing task                                  source=registry.xxxxxx.com target="registry1.xxxxxx.com" task=sync-lab
INFO[0000] mapping                                       from=/sync/alpine to=/alpine-synctest
INFO[0000] refreshing credentials                        registry=registry.xxxxxx.com
INFO[0000] refreshing credentials                        registry="registry1.xxxxxx.com"
INFO[0001] syncing tag                                   tag=3.14
DEBU[0002] Getting image source signatures
DEBU[0003] Copying blob sha256:ce42088e28cfff1fd4a25fe4aa16b527c4ddb72ee25d6045588985e20add021b
DEBU[0003] Copying config sha256:cc924c6569616daebad97cf976a78b70a612caf562d91615d363b5478d8f2c2a
DEBU[0004] Writing manifest to image destination
DEBU[0004] Storing signatures
INFO[0004] waiting for next sync task...
DEBU[0060] task firing                                   task=sync-lab
INFO[0060] syncing task                                  source=registry.xxxxxx.com target="registry1.xxxxxx.com" task=sync-lab
INFO[0060] mapping                                       from=/sync/alpine to=/alpine-synctest
INFO[0060] refreshing credentials                        registry=registry.xxxxxx.com
INFO[0060] refreshing credentials                        registry="registry1.xxxxxx.com"
INFO[0061] syncing tag                                   tag=3.14
DEBU[0062] Getting image source signatures
DEBU[0065] Copying blob sha256:ce42088e28cfff1fd4a25fe4aa16b527c4ddb72ee25d60455
88985e20add021b
DEBU[0066] Copying config sha256:cc924c6569616daebad97cf976a78b70a612caf562d91615d363b5478d8f2c2a
DEBU[0067] Writing manifest to image destination
DEBU[0067] Storing signatures
INFO[0067] waiting for next sync task...
DEBU[0120] task firing                                   task=sync-lab
INFO[0120] syncing task                                  source=registry.xxxxxx.com target="registry1.xxxxxx.com" task=sync-lab
INFO[0120] mapping                                       from=/sync/alpine to=/alpine-synctest
INFO[0120] refreshing credentials                        registry=registry.xxxxxx.com
INFO[0120] refreshing credentials                        registry="registry1.xxxxxx.com"
INFO[0121] syncing tag                                   tag=3.14
DEBU[0122] Getting image source signatures
DEBU[0123] Copying blob sha256:ce42088e28cfff1fd4a25fe4aa16b527c4ddb72ee25d6045588985e20add021b
DEBU[0123] Copying config sha256:cc924c6569616daebad97cf976a78b70a612caf562d91615d363b5478d8f2c2a
DEBU[0124] Writing manifest to image destination
DEBU[0124] Storing signatures
INFO[0124] waiting for next sync task...
^C
INFO[0161] received signal, stopping ...                 signal=interrupt
DEBU[0161] stopping tasks
DEBU[0161] task exiting                                  task=sync-lab
DEBU[0161] task exited                                   task=sync-lab
INFO[0161] all done
DEBU[0161] exit main

Support parallel tasks

I'm working on a solution to synchronize images to a set of remote registries, and having the ability to run tasks in parallel would be a huge help. Right now I'm building n different configs and running m instances of dregsy. It would be much cleaner to have a single config will all of my tasks defined and have dregsy handle managing the parallelism.

Something along the lines of:

relay: skopeo

skopeo:
  binary: skopeo
  mode: copy
  # Number of tasks to run in parallel
  parallel_tasks: 4

attempt to sync nexus docker registry

I'm trying to synchronize docker registry, but I'm getting fail

2020-07-27T16:10:11Z [INFO]
2020-07-27T16:10:41Z [INFO] task 'task1' fired too soon, skipping
2020-07-27T16:10:41Z [INFO] waiting for next sync task...
2020-07-27T16:10:41Z [INFO]
2020-07-27T16:11:41Z [INFO] syncing task 'task1': '10.10.10.10:5000' --> '10.20.20.20:5000'
2020-07-27T16:11:41Z [INFO] mapping '/dev/app' to '/dev/app'
2020-07-27T16:11:41Z [INFO] pulling source image '10.10.10.10:5000/dev/app'
64: Pulling from dev/app
Digest: sha256:033952a79c057676881dd67340e92dab53e6385564575a3d3f9d99a4cece3b30
65: Pulling from dev/app
Digest: sha256:d383efc0a584ca9424a1282028ae549272a4cdad38e26bf20709e8d834ff3010
72: Pulling from dev/app
Digest: sha256:e0ad897b05da6a4829af49ee4f71e10d06ed4710b35f3cb883a0380bdad33c50
74: Pulling from dev/app
Digest: sha256:53008ada6c3dfa96ecb96b6c51f43809791ea5cee83d8ef1fad3c8a24cc20b05
Status: Image is up to date for 10.10.10.10:5000/dev/app
2020-07-27T16:11:41Z [INFO] relevant tags
2020-07-27T16:11:41Z [ERROR] error listing all tags of source image '10.10.10.10:5000/dev/app': malformed image ref: invalid reference format
2020-07-27T16:11:41Z [ERROR] error pushing target image: An image does not exist locally with the tag: 10.20.20.20:5000/dev/app
2020-07-27T16:11:41Z [INFO] setting tags for target image '10.20.20.20:5000/dev/app'
2020-07-27T16:11:41Z [INFO] pushing target image '10.20.20.20:5000/dev/app'
The push refers to repository [10.20.20.20:5000/dev/app]
2020-07-27T16:11:41Z [INFO]
2020-07-27T16:11:41Z [INFO] waiting for next sync task...
2020-07-27T16:11:41Z [INFO]



# relay type, either 'skopeo' or 'docker'
relay: docker

docker:
  # Docker host to use as the relay
  dockerhost: unix:///var/run/docker.sock
  # Docker API version to use, defaults to 1.24
  api-version: 1.24

# list of sync tasks
tasks:

  - name: task1 # required

    # interval in seconds at which the task should be run; when omitted,
    # the task is only run once at start-up
    interval: 60

    # determines whether for this task, more verbose output should be
    # produced; defaults to false when omitted
    verbose: true

    # 'source' and 'target' are both required and describe the source and
    # target registries for this task:
    #  - 'registry' points to the server; required
    #  - 'auth' contains the base64 encoded credentials for the registry
    #    in JSON form {"username": "...", "password": "..."}
    #  - 'auth-refresh' specifies an interval for automatic retrieval of
    #    credentials; only for AWS ECR (see below)
    #  - 'skip-tls-verify' determines whether to skip TLS verification for the
    #    registry server (only for 'skopeo', see note below); defaults to false
    source:
      registry: 10.10.10.10:5000
      auth: YYYYWRtaW46TmNZMTMwcnI=
    #  skip-tls-verify: true
    target:
      registry: 10.20.20.20:5000
      auth: YYYYWRtaW46TmNZMTMwcnI=
    #  skip-tls-verify: true

    # 'mappings' is a list of 'from':'to' pairs that define mappings of image
    # paths in the source registry to paths in the destination; 'from' is
    # required, while 'to' can be dropped if the path should remain the same as
    # 'from'. Additionally, the tags being synced for a mapping can be limited
    # by providing a 'tags' list. When omitted, all image tags are synced.
    mappings:
      - from: dev/app 

docker run --privileged --rm -v /var/run/docker.sock:/var/run/docker.sock dregsy:0.3.0

platform architecture destination tag labeling

hi, i was wondering if dregsy has the ability to label the destination tag based on different architecture, so for instance tag (v4.7, amd64), (v4.6,aarch) when specifying platform: all in the config.yaml.

Thanks.

Error syncing entire namespace

I have set up a namespace in my Quay registry that I want to sync to a remote Nexus3 registry. Things work fine if I specify a specific repo in my source registry, but not if I specify a namespace or a regex into that namespace.

For example, this:

    mappings:
      - from: regex:sync/.*
        to: regex:sync/(.*),synctest-$1

give me this error:

ERRO[0000] error getting catalog page: GET https://registry.xxxxxx.com/v2/auth?scope=registry%3Acatalog%3A%2A&service=registry.xxxxxx.com: INVALID_REQUEST: Unable to decode repository and actions: registry:catalog:*; map[]

If I change the mapping to:

    mappings:
      - from: sync/alpine
        to: regex:sync/(.*),synctest-$1

It will sync the alpine repo correctly.

Any idea what might be going on? I am assuming this has something to do with the way Quay is responding to the wildcard request, but want to make sure before I go open a ticket with RedHat.

I am using a local build of dregsy built from the master branch in GitHub and skopeo 1.4.1.

Update ubuntu sha256 to mitigate High security findings

Hello,

thank you very much on this very cool tool :)!

Recently there were some high findings related to ubuntu base images:
https://ubuntu.com/security/CVE-2022-3786
https://ubuntu.com/security/CVE-2022-3602

so to mitigate those, can you please, update sha256 version of ubuntu base image to latest one:
ubuntu@sha256:7cfe75438fc77c9d7235ae502bf229b15ca86647ac01c844b272b56326d56184

and release a new version :)

I have tried out and its working fine + no more security findings.

Add command line flag to limit tasks

I have a dregsy yaml file that syncs to 5 different docker registries. From time to time, I would like to be able to run a manual sync to just one or two of them w/o having to extract that data to a separate yaml file. It would be very useful to be able to specify which tasks to run from the command line. I'm thinking something along the lines of what anisble-playbook uses:
dregsy --config regsync.yml --limit sync-registry2

Add multiarch support

ARM64 architecture becomes very popular and AWS EKS/ECR already supports this. So, syncing AMD64+ARM64 is good idea.
https://docs.docker.com/docker-for-mac/multi-arch/

Skopeo is already supports this feature. So, it needs to bypass "--all" from Dregsy command line to Skopeo.

skopeo copy
options:
--all
If source-image refers to a list of images, instead of copying just the image which matches the current OS and architecture (subject to the use of the global --override-os, --override-arch and --override-variant options), attempt to copy all of the images in the list, and the list itself.

GCP auth per target and source

Hi, i would like to use the tool to sync between two registries that i have on GCP, the issue is each of them sits in a different project.
An option to set the authentication configuration for each of them would allow me two authenticate separately to each project with the least privileges.

unexpected end of JSON input

Any idea where an error like the one above would be coming from? It seems like things are syncing, but I see that in the logs for every repository.

time="2022-02-24T00:21:26Z" level=info msg="syncing task" source=123456789012.dkr.ecr.us-east-1.amazonaws.com target="remotereg01.example.com:8083" task=sync-wonder
time="2022-02-24T00:21:26Z" level=info msg=mapping from="regex:syncbase/.*" to="regex:syncbase/(.+)/[^/]*$,$1/"
time="2022-02-24T00:21:26Z" level=info msg="refreshing credentials" registry=123456789012.dkr.ecr.us-east-1.amazonaws.com
time="2022-02-24T00:21:29Z" level=info msg="refreshing credentials" registry="remotereg01.example.com:8083"
time="2022-02-24T00:21:29Z" level=debug msg="retrieving repository list"
time="2022-02-24T00:21:29Z" level=debug msg="ECR retrieving image list"
time="2022-02-24T00:21:32Z" level=debug msg="caching repository list"
time="2022-02-24T00:21:32Z" level=error msg="unexpected end of JSON input"
time="2022-02-24T00:21:32Z" level=error msg="unexpected end of JSON input"
time="2022-02-24T00:21:32Z" level=info msg="syncing tag" tag=21.10.0
time="2022-02-24T00:21:32Z" level=debug msg="time=\"2022-02-24T00:21:32Z\" level=info msg=\"Tag presence check\" imagename=\"123456789012.dkr.ecr.us-east-1.amazonaws.com/syncbase/appdynamics/cluster-agent:21.10.0\" tagged=true"
time="2022-02-24T00:21:32Z" level=debug msg="time=\"2022-02-24T00:21:32Z\" level=info msg=\"Copying image ref 1/1\" from=\"docker://123456789012.dkr.ecr.us-east-1.amazonaws.com/syncbase/appdynamics/cluster-agent:21.10.0\" to=\"docker://remotereg01.example.com:8083/appdynamics/cluster-agent:21.10.0\""
time="2022-02-24T00:21:33Z" level=debug msg="Getting image source signatures"
time="2022-02-24T00:21:37Z" level=debug msg="Skipping: image already present at destination"
time="2022-02-24T00:21:37Z" level=debug msg="time=\"2022-02-24T00:21:37Z\" level=info msg=\"Synced 1 images from 1 sources\""
time="2022-02-24T00:21:37Z" level=error msg="unexpected end of JSON input"
time="2022-02-24T00:21:37Z" level=info msg="syncing tag" tag=0.6.11

Ignore immutable registry errors when source image changed with a flag or configuration

Hi all,

I've encountered an issue uploading images to my immutable registry.

When the source image gets changed for whatever reason dregsy tries reuploading the image but fails because the image tag already exists and can't be overwritten.

Log message:

The image tag '1.20.12' already exists in the 'xxxxxx/kubectl' repository and cannot be overwritten because the repository is immutable.

I think there should be a configuration/flag available to ignore errors like this and simply drop a warning at the end saying something like:

The source image for <insert repo name> was changed in < tag version >. The image was not uploaded because the target registry is immutable.

But this should not be an error just a warning.
I suggest a new field for the configuration of dregsy tasks something like this:

"tasks": {
  [
    "source": {
      "regsitry": "my-registry.com",
      "auth": "xxxxxxxxx"
    },
    "target": {
      "registry": "my-traget-registry.com",
      "auth": "xxxxxxxxx",
      "immutable": true
    },
    ...
  ]
}

or simply a flag called "ignoreImmutable" or something like this.

Let me know what you think.

Syncing GCP repositories

I'm trying to sync docker images from the Google Container Registry (us.gcr.io) using a service account (https://cloud.google.com/container-registry/docs/advanced-authentication). There is "auth" with encoded json:

_json_key:{
  "type": "service_account",
  "project_id": "...
  ...
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
 ...

Any chance to set up synchronization with GCP repos? I tried skopeo and docker driver without success.

My errors:

2019-09-06T10:22:38Z [ERROR] invalid character '_' looking for beginning of value
2019-09-06T10:22:39Z [ERROR] error listing image tags: time="2019-09-06T10:22:39Z" level=fatal msg="Error reading manifest latest in us.gcr.io/xxx: unauthorized: You don't have the needed permissions to perform this operation, and you may have invalid credentials. To authenticate your request, follow the steps in: https://cloud.google.com/container-registry/docs/advanced-authentication" 

and with docker as relay:

2019-09-06T10:23:35Z [ERROR] error pulling source image 'us.gcr.io/xxx': Error response from daemon: pull access denied for us.gcr.io/xxx, repository does not exist or may require 'docker login'

docker daemon:

denied: Failed to read tags for host 'us.gcr.io', repository '/v2/xxx/tags/list'"

Thanks.

docker build fails

I've tried to build the docker image but it fails. Unfortunately I'm not into go and its tools.

docker build  -t dregsy .
Sending build context to Docker daemon  176.1kB

Step 1/11 : FROM golang:1.10 as builder
1.10: Pulling from library/golang
54f7e8ac135a: Pulling fs layer
d6341e30912f: Pulling fs layer
087a57faf949: Pulling fs layer
5d71636fb824: Pulling fs layer
f368dba6a331: Pulling fs layer
1ea0c245e5c5: Pulling fs layer
f81588ba3d2a: Pulling fs layer
5d71636fb824: Waiting
f368dba6a331: Waiting
1ea0c245e5c5: Waiting
f81588ba3d2a: Waiting
087a57faf949: Verifying Checksum
087a57faf949: Download complete
d6341e30912f: Verifying Checksum
d6341e30912f: Download complete
54f7e8ac135a: Verifying Checksum
54f7e8ac135a: Download complete
f368dba6a331: Verifying Checksum
f368dba6a331: Download complete
5d71636fb824: Verifying Checksum
5d71636fb824: Download complete
f81588ba3d2a: Verifying Checksum
f81588ba3d2a: Download complete
1ea0c245e5c5: Verifying Checksum
1ea0c245e5c5: Download complete
54f7e8ac135a: Pull complete
d6341e30912f: Pull complete
087a57faf949: Pull complete
5d71636fb824: Pull complete
f368dba6a331: Pull complete
1ea0c245e5c5: Pull complete
f81588ba3d2a: Pull complete
Digest: sha256:dc6610eb1389be884a520e4c8846739d1834128a6ab2cc0a937fb52e231904c0
Status: Downloaded newer image for golang:1.10
 ---> 0a19f4d16598
Step 2/11 : LABEL stage=intermediate
 ---> Running in 78cd1d931e35
Removing intermediate container 78cd1d931e35
 ---> 393d5664ee6c
Step 3/11 : COPY . $GOPATH/src/github.com/xelalexv/dregsy/
 ---> c1aab0ab6287
Step 4/11 : WORKDIR $GOPATH/src/github.com/xelalexv/dregsy/
 ---> Running in 27c9fe1dc4c1
Removing intermediate container 27c9fe1dc4c1
 ---> d0af0c5349b4
Step 5/11 : RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -a 	-tags netgo -installsuffix netgo -ldflags '-w' 	-o /go/bin/dregsy ./cmd/dregsy/
 ---> Running in 8bb6d29501d8
internal/pkg/sync/config.go:17:2: cannot find package "github.com/aws/aws-sdk-go/aws" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/github.com/aws/aws-sdk-go/aws (vendor tree)
	/usr/local/go/src/github.com/aws/aws-sdk-go/aws (from $GOROOT)
	/go/src/github.com/aws/aws-sdk-go/aws (from $GOPATH)
internal/pkg/sync/config.go:18:2: cannot find package "github.com/aws/aws-sdk-go/aws/awserr" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/github.com/aws/aws-sdk-go/aws/awserr (vendor tree)
	/usr/local/go/src/github.com/aws/aws-sdk-go/aws/awserr (from $GOROOT)
	/go/src/github.com/aws/aws-sdk-go/aws/awserr (from $GOPATH)
internal/pkg/sync/config.go:19:2: cannot find package "github.com/aws/aws-sdk-go/aws/session" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/github.com/aws/aws-sdk-go/aws/session (vendor tree)
	/usr/local/go/src/github.com/aws/aws-sdk-go/aws/session (from $GOROOT)
	/go/src/github.com/aws/aws-sdk-go/aws/session (from $GOPATH)
internal/pkg/sync/config.go:20:2: cannot find package "github.com/aws/aws-sdk-go/service/ecr" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/github.com/aws/aws-sdk-go/service/ecr (vendor tree)
	/usr/local/go/src/github.com/aws/aws-sdk-go/service/ecr (from $GOROOT)
	/go/src/github.com/aws/aws-sdk-go/service/ecr (from $GOPATH)
internal/pkg/relays/docker/docker.go:16:2: cannot find package "github.com/docker/docker/api/types" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/github.com/docker/docker/api/types (vendor tree)
	/usr/local/go/src/github.com/docker/docker/api/types (from $GOROOT)
	/go/src/github.com/docker/docker/api/types (from $GOPATH)
internal/pkg/relays/docker/docker.go:17:2: cannot find package "github.com/docker/docker/client" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/github.com/docker/docker/client (vendor tree)
	/usr/local/go/src/github.com/docker/docker/client (from $GOROOT)
	/go/src/github.com/docker/docker/client (from $GOPATH)
internal/pkg/relays/docker/docker.go:18:2: cannot find package "github.com/docker/docker/pkg/jsonmessage" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/github.com/docker/docker/pkg/jsonmessage (vendor tree)
	/usr/local/go/src/github.com/docker/docker/pkg/jsonmessage (from $GOROOT)
	/go/src/github.com/docker/docker/pkg/jsonmessage (from $GOPATH)
internal/pkg/log/log.go:13:2: cannot find package "golang.org/x/crypto/ssh/terminal" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/golang.org/x/crypto/ssh/terminal (vendor tree)
	/usr/local/go/src/golang.org/x/crypto/ssh/terminal (from $GOROOT)
	/go/src/golang.org/x/crypto/ssh/terminal (from $GOPATH)
internal/pkg/sync/config.go:14:2: cannot find package "gopkg.in/yaml.v2" in any of:
	/go/src/github.com/xelalexv/dregsy/vendor/gopkg.in/yaml.v2 (vendor tree)
	/usr/local/go/src/gopkg.in/yaml.v2 (from $GOROOT)
	/go/src/gopkg.in/yaml.v2 (from $GOPATH)
The command '/bin/sh -c CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -a 	-tags netgo -installsuffix netgo -ldflags '-w' 	-o /go/bin/dregsy ./cmd/dregsy/' returned a non-zero code: 1

sync the whole registry

Is there a way to sync the full registry? I tried from: * and from: regex:* but this errors happen:

time="2021-04-07T23:20:18Z" level=info msg=mapping from="/*" to="/*"                                     
time="2021-04-07T23:20:18Z" level=error msg="error listing image tags for ref 'source/*': time=\"2021-04-07T23:20:18Z\" level=fatal msg=\"invalid reference format\"\n, exit status 1"                                                                                                  
time="2021-04-07T23:20:18Z" level=error msg="one or more tasks had errors, please see log for details"
time="2021-04-07T23:31:43Z" level=info msg=mapping from="/regex:*" to="/regex:*"                         
time="2021-04-07T23:31:43Z" level=error msg="error listing image tags for ref 'source/regex:*': time=\"2021-04-07T23:31:43Z\" level=fatal msg=\"invalid reference format\"\n,exit status 1"
relay: skopeo
tasks:
  - name: sync # required
    verbose: true
    source:
      registry: source
      skip-tls-verify: true
    target:
      registry: target
      skip-tls-verify: true
    mappings:
      - from: "*"

Repo name duplication when using wildcards

I am seeing some very odd duplication of repo names now that I have wildcards working (I moved to using eco.io as my source repo). For example with the config below, I see it trying to do this sync:

time="2022-02-08T17:45:04Z" level=info msg=mapping from="regex:myrepo/.*" to="regex:myrepo/(.+),$1/"
time="2022-02-08T17:45:04Z" level=info msg="refreshing credentials" registry=123456789.dkr.ecr.us-east-1.amazonaws.com
time="2022-02-08T17:45:07Z" level=info msg="refreshing credentials" registry="registry1.example.com:8083"
time="2022-02-08T17:45:07Z" level=debug msg="retrieving repository list"
time="2022-02-08T17:45:07Z" level=debug msg="ECR retrieving image list"
time="2022-02-08T17:45:10Z" level=debug msg="caching repository list"
time="2022-02-08T17:45:10Z" level=info msg="syncing tag" tag=5.0.6-alpine
time="2022-02-08T17:45:10Z" level=debug msg="time=\"2022-02-08T17:45:10Z\" level=info msg=\"Tag presence check\" imagename=\"123456789.dkr.ecr.us-east-1.amazonaws.com/myrepo/baserepo/redis:5.0.6-alpine\" tagged=true"
time="2022-02-08T17:45:10Z" level=debug msg="time=\"2022-02-08T17:45:10Z\" level=info msg=\"Copying image ref 1/1\" from=\"docker://123456789.dkr.ecr.us-east-1.amazonaws.com/myrepo/baserepo/redis:5.0.6-alpine\" to=\"docker://registry1.example.com:8083/baserepo/redis/redis:5.0.6-alpine\""

notice the redis/redis on the last line. I would expect that to just be baserepo/redis:5.0.6-alpine.

My config:

docker:
  api-version: '1.24'
  dockerhost: unix:///var/run/docker.sock
lister:
  cacheDuration: 1h
  maxItems: 100
relay: skopeo
skopeo:
  binary: skopeo
  mode: sync
tasks:
  - name: sync-reg1
    interval: 1800
    source:
      registry: 123456789.dkr.ecr.us-east-1.amazonaws.com
      auth-refresh: 1h
    target:
      registry: registry1.example.com:8083
    mappings:
    - from: regex:myrepo/.*
      to: regex:myrepo/(.+),$1/
    verbose: true

I have tried the to: regex with and without the trailing slash, it doesn't seem to make a difference. From the docs, and my earlier testing when I wasn't using a regex for the from: config, I would think this should work. I'm going try try something crazy like this next to: regex:myrepo/(.+)/[^/]*$,$1. But I'm afraid that will end up syncing /baserepo:5.0.6-alpine in the example above.

Any ideas why it's doubling the repo name?

closing one-off task causes panic: close of nil channel

hi, i'm using your tool to sync a bunch of docker images from dockerhub to ecr.
It worked fine till a certain point where it get this panic: close of nil channel

The following is part of the log.

... a whole bunch of successful syncs ...
08:22:40  time="2020-12-11T07:22:40Z" level=debug msg="Copying config sha256:38983bba610e04c6bd00ef5c26b86ad5cbff75cb6b83431595d6fca744a6f135"
08:22:40  time="2020-12-11T07:22:40Z" level=debug msg="Writing manifest to image destination"
08:22:40  time="2020-12-11T07:22:40Z" level=debug msg="Storing signatures"
08:22:40  time="2020-12-11T07:22:40Z" level=debug msg="stopping tasks" func="github.com/xelalexv/dregsy/internal/pkg/sync.(*Sync).SyncFromConfig" file="/go/src/dregsy/internal/pkg/sync/sync.go:149"
08:22:40  panic: close of nil channel
08:22:40  
08:22:40  goroutine 1 [running]:
08:22:40  github.com/xelalexv/dregsy/internal/pkg/sync.(*Task).stopTicking(0xc0000bdf00)
08:22:40  	/go/src/dregsy/internal/pkg/sync/task.go:138 +0x40
08:22:40  github.com/xelalexv/dregsy/internal/pkg/sync.(*Sync).SyncFromConfig(0xc0003a02e0, 0xc0001d4ea0, 0x0, 0x0)
08:22:40  	/go/src/dregsy/internal/pkg/sync/sync.go:152 +0x59b
08:22:40  main.main()
08:22:40  	/go/src/dregsy/cmd/dregsy/main.go:113 +0x24f

This is my config file

relay: skopeo
tasks:
  - name: task1
    verbose: true
    source:
      registry: docker.io
    target:
      registry: 754813824532.dkr.ecr.eu-west-1.amazonaws.com
      auth-refresh: 10h
    mappings:
      - from: alpine
        tags: ['latest']
      - from: postman/newman
        tags: ['latest','5-alpine']
      - from: aequitas/http-api-resource
        tags: ['latest']
      - from: python
        tags: ['2.7.13-alpine','3-alpine']
      - from: node
        tags: ['10-alpine']
      - from: skyscrapers/apt-package-resource
        tags: ['latest']
      - from: maven
        tags: ['3.6.3-jdk-8','3.5.2-jdk-8','3.6.3-jdk-11']
      - from: openapitools/openapi-generator-cli
        tags: ['v4.3.1']
      - from: selenium/standalone-chrome
        tags: ['3.141.59-20200719']
      - from: mysql
        tags: ['5.7']
      - from: pjpinten/packer-g10k
        tags: ['1.2']
      - from: renovate/renovate
        tags: ['latest']

It is ran as a jenkins job, so i do the scheduling there. This is a one shot job.
Jenkins executes:

docker run --rm -v /opt/jenkins/workspace/ose-Concourse_sync-docker_master/config.yaml:/config.yaml -e LOG_METHODS=true -e LOG_LEVEL=trace -e AWS_ACCESS_KEY_ID=**** -e AWS_SECRET_ACCESS_KEY=**** xelalex/dregsy

Running this on my local machine works fines so maybe there is some kind of weird race condition?
I'm not to familiar with go. But it seems that there are timers (threads) in use which might cause this.
For me this is not really blocking as the sync itself works fine but the command does fail.
This is not very clean and my team asks questions about it.

No output from skopeo, even with increased logging

Hey, first of all thank you for this project!
We hit the docker rate limit today, but it took us a while to figure it out because there were no logs from Skopeo shown, even with increased logging. All we got was output like this:

time="2022-07-29T09:14:10Z" level=info msg=mapping from=/busybox to=/busybox
time="2022-07-29T09:14:10Z" level=info msg="refreshing credentials" registry=docker.io
time="2022-07-29T09:14:10Z" level=info msg="refreshing credentials" registry=12345678910.dkr.ecr.eu-west-1.amazonaws.com
time="2022-07-29T09:14:10Z" level=info msg="target already exists" ref=12345678910.dkr.ecr.eu-west-1.amazonaws.com/busybox
time="2022-07-29T09:14:10Z" level=info msg="syncing tag" platform=all tag=latest
time="2022-07-29T09:14:50Z" level=error msg="exit status 1"
time="2022-07-29T09:14:50Z" level=error msg="errors during sync"

Only when I modified these lines to os.Stdout & os.Stderr I was able to see the Skopeo output. It's too much to show the user everything, but maybe it's better to buffer the output and print it if there was an error? We felt a bit mocked when it said "something failed, but I won't tell you what" 😄

Support string filtering on top of semver tag filtering

Problem: I want to sync all node images with semver constraints >=12.19.x || >=14.15.x and only if the tag name contains alpine or -buster.
This is currently not possible with the tag filtering .

One could use the regex feature:

- 'regex: 12\.19\.[0-9]-(alpine|buster)'
- 'regex: 14\.15\.[0-9]-(alpine|buster)'

however for every new node minor version we would have to modify that list so that it stays up to date.
Is there any way to achieve the desired outcome with the current tag filtering?

Unable to sync insecure registries

There should be an option to set registries as insecure registries, something like:

tasks:
  - name: task1
    source:
      registry: my_fancy_registry
      insecure: no
    target:
      registry: my_not_so_fancy_registry:5000
      insecure: yes

So the client would do http instead of https for the target registry in my example

Provide a non-alpine image?

I would like to use your docker container with the aws cli so I can perform a ECR login with role based auth. I think this would be a pretty common use case for this tool. Unfortunately AWS do not provide a binary which will work on docker images based on Alpine because they're compiling them against glibc. Hacking this into an alpine image is very cumbersome and not very easy to document aws/aws-cli#4971 aws/aws-cli#4685

It would be great if we could get a non-alpine based image for people wanting to use your tool with AWS.

Attach repository policies to repository created in ECR

Hello! I am working on syncing images from Dockerhub/quay.io to ECR. However, I would need to attach an ECR Repository Policy to the repositories created by Dregsy - as far as I understand dregsy can not do this yet.

I am not too sure how to add this to the configuration file. Since policies are per-repository, I could need to add a configuration element to the mapping section - also, there could be several, so it should be an array?

mappings:
  - from: test/image
    to: archive/test/image
    [policies|ecr_policies]:
    - /path/to/policy.json 

Is this something you would be willing to accept as a Pull Request? I would love your input.
Many thanks!

Build Skopeo binary as part of dregsy build

Recently, it has become difficult to keep the exact same version of Skopeo in both the Ubuntu and Alpine based container images released for dregsy. Also, the Skopeo versions offered in both package managers are far behind the latest Skopeo release, which delays the adoption of new Skoepo features. We should therefore start again to build the Skopeo binary as part of the dregsy build. This should be fairly straightforward using Docker multistage builds.

Omitting tag during sync results in an error when using skopeo, works using docker

The documentation states that if the tag is omitted all tags will be synced.

I am syncing from aws ecr to artifactory, when I provide a tag the sync works, when I don't it does not.

working:

    # paths in the source registry to paths in the destination; 'from' is
    # required, while 'to' can be dropped if the path should remain the same as
    # 'from'. Additionally, the tags being synced for a mapping can be limited
    # by providing a 'tags' list. When omitted, all image tags are synced.
    mappings:
      - from: dev-image1
        to: dev-image1
        tags: ['0snapshot-dev']
#      - from: test/another-image
docker run --rm -v ./config.yaml:/config.yaml  xelalex/dregsy
2020-05-08T15:37:34Z [INFO] 
2020-05-08T15:37:34Z [INFO] skopeo version 0.1.32
2020-05-08T15:37:34Z [INFO] skopeo relay ready
2020-05-08T15:37:34Z [INFO] syncing task 'task1': 'ecr.aws.com' --> 'destination.com'
2020-05-08T15:37:34Z [INFO] mapping '/dev-image1' to '/dev-image1'
2020-05-08T15:37:34Z [INFO] 
2020-05-08T15:37:34Z [INFO] syncing tag '0snapshot-dev':
Getting image source signatures
Skipping fetch of repeat blob sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b
Skipping fetch of repeat blob sha256:6cd6a943ce277e76a108b1c860c5991d3c9acae2db14865c7a6d4a2231b38ff2
Skipping fetch of repeat blob sha256:a50b5ac4a7fb2ab0d0cc3f2d3c1063d9f7751e32fe038b7ad7545bb239027167
Skipping fetch of repeat blob sha256:a2713a4ab6152352dc7660cb029cda5ba26bb7d7dbeb80ff38678f052dac97e5
Skipping fetch of repeat blob sha256:2db755cb04039e83097e96b20cc3bffb5752498fa1e0105356447b2d9df4f0fd
Skipping fetch of repeat blob sha256:a7febb4cdc5f9be8051af037bf73b9a69644283b223b6866504d67d025a91d5d
Copying config sha256:20d5fe6d7deec98a85813f251ec3264505c4bc6fbc8dda7061c0a3c0a81fed1e
 0 B / 7.22 KB  0s
Writing manifest to image destination
Storing signatures
2020-05-08T15:37:47Z [INFO] 
2020-05-08T15:37:47Z [INFO] all done

not working:

# 'mappings' is a list of 'from':'to' pairs that define mappings of image
    # paths in the source registry to paths in the destination; 'from' is
    # required, while 'to' can be dropped if the path should remain the same as
    # 'from'. Additionally, the tags being synced for a mapping can be limited
    # by providing a 'tags' list. When omitted, all image tags are synced.
    mappings:
      - from: dev-image1
        to: dev-image1
#        tags: ['0snapshot-dev']
#      - from: test/another-image
docker run --rm -v .config.yaml:/config.yaml  xelalex/dregsy
2020-05-08T15:43:11Z [INFO] 
2020-05-08T15:43:11Z [INFO] skopeo version 0.1.32
2020-05-08T15:43:11Z [INFO] skopeo relay ready
2020-05-08T15:43:11Z [INFO] syncing task 'task1': 'ecr.aws.com' --> 'destination.com'
2020-05-08T15:43:11Z [INFO] mapping '/dev-image1' to '/dev-image1'
2020-05-08T15:43:12Z [INFO] 
2020-05-08T15:43:12Z [INFO] all done
2020-05-08T15:43:12Z [ERROR] error listing image tags: time="2020-05-08T15:43:12Z" level=fatal msg="Error reading manifest latest in ecr.aws.com/dev-image1: manifest unknown: Requested image not found" 
, exit status 1

unauthorized to list catalog

Hello I get a "unauthorized to list catalog",

i want to sync images from a harbor instance, the login is correct (checked several times, i can push to it with the same credentials), the link works too.

level=error msg="error getting catalog page: GET https://hub.domain.com/v2/_catalog?last=&n=100: UNAUTHORIZED: unauthorized to list catalog"

to the config:

i would like to syncronize two namespaces with the help of regex, harbor itself offers this possibility only very limited.

?last=&n=100
what still surprises me is that the number of tags to be retrieved is set to 100, even though 1000 is set in the config.

i use the latest xelalex/dregsy docker image version

in another sync job, i push to the same harbor instance, that works.

But with the list there are problems

I hope you can help me

AWS ECR example in documentation

Will be good in AWS ECR example to describe whole process how it should look, like:

  • how dregsy config should look
  • what additional commands i must do like aws login or something (or is dregsy doing it for me)
  • what more?

docker relay: can't use docker.io as source

Tested pulling from DockerHub and pushing to a private GitLab, using docker relay.
It seems the tool has problems with retagging images named docker.io/user/image.
I found the problem in docker.go: client.listImages(): it takes the image from config file docker.io/usr/image and tries to match it with an image on docker host, which is saved as usr/image.

exit status 1 when pushing to GAR

hi @xelalexv thx for the awesome tool btw.

when running docker run commands based on the base64 method as shown in #51
docker run --rm -e LOG_LEVEL=debug -e GOOGLE_APPLICATION_CREDENTIALS=base64 -v <absolute path to yaml>:/config.yaml xelalex/dregsy

with the config of:

relay: skopeo


tasks:

  - name: test # required
    verbose: true
    source:
      registry: registry.hub.docker.com
    target:
      registry:  us-central1-docker.pkg.dev
      auth: none
    mappings:
    - from: library/alpine
      to:  registry/docker/library/alpine
      tags: ['latest']

I am receiving 403s

time="2023-02-09T10:37:43Z" level=info msg="dregsy 0.4.4"
time="2023-02-09T10:37:43Z" level=info msg="skopeo version 1.9.3\n"
time="2023-02-09T10:37:43Z" level=info msg="relay ready" relay=skopeo
time="2023-02-09T10:37:43Z" level=info msg="syncing task" source=registry.hub.docker.com target=us-central1-docker.pkg.dev task=test
time="2023-02-09T10:37:43Z" level=info msg=mapping from=/library/alpine to=/registry/docker/library/alpine
time="2023-02-09T10:37:43Z" level=info msg="refreshing credentials" registry=registry.hub.docker.com
time="2023-02-09T10:37:43Z" level=info msg="refreshing credentials" registry=us-central1-docker.pkg.dev
time="2023-02-09T10:37:43Z" level=debug msg="verbatim tags: [latest]"
time="2023-02-09T10:37:43Z" level=debug msg="pruned tags: []"
time="2023-02-09T10:37:43Z" level=debug msg="expanded tags: [latest]"
time="2023-02-09T10:37:43Z" level=info msg="syncing tag" platform= tag=latest
time="2023-02-09T10:37:55Z" level=debug msg="Getting image source signatures"
time="2023-02-09T10:37:55Z" level=debug msg="Copying blob sha256:8921db27df2831fa6eaa85321205a2470c669b855f3ec95d5a3c2b46de0442c9"
time="2023-02-09T10:37:56Z" level=debug msg="time=\"2023-02-09T10:37:56Z\" level=fatal msg=\"copying system image from manifest list: trying to reuse blob sha256:8921db27df2831fa6eaa85321205a2470c669b855f3ec95d5a3c2b46de0442c9 at destination: Requesting bearer token: invalid status code from registry 403 (Forbidden)\""
time="2023-02-09T10:37:56Z" level=error msg="exit status 1"
time="2023-02-09T10:37:56Z" level=error msg="errors during sync"
time="2023-02-09T10:37:56Z" level=debug msg="stopping tasks"

loggin into the destination registry has no problems as shown below:

› cat base64.json | skopeo login -u _json_key_base64 --password-stdin https://us-central1-docker.pkg.dev
Login Succeeded!

and the roles of Cloud Build Service Agent, Storage Object Admin, and Artifact Registry Repository Administrator have been granted to the service account. Is there anything that is missing?

Can the source of mappings use a pattern ?

Suppose I want to synchronize all repositories that are in a sub path : can I describe my mappings with one rule using a pattern or must I enumerate all the mappings (one by repository).
Can I have

mappings:
  - from: library/*

instead of

mappings:
  - from: library/repo1
  - from: library/repo2
  ....
  - from: library/repo99

Skopeo version needs push

Currently used version uses and old version using ubuntu 17.10. Build fails on git update due to that.

Webhook support

Hi @xelalexv, thanks for providing this tool which has a lot of helpers for ECR compared to "raw Skopeo" (mainly update auth tokens and creating a repo if does not exist).

At Padoa, we are using it to keep in sync repositories from 2 distinct cloud provider managed registry instances: Azure Container Registry to AWS ECR.
The best way we found currently is to send a webhook at each manifest push on the origin so that it triggers a sync of the pushed tag. We hence added a support for incoming webhook as well as support for multiple parallel sync.

It is still a draft (we also need to update doc) and work is in progress but tell us if it is something you would like to include in the original dregsy, and how we can contribute in this way if so.

The fork is available here: https://github.com/padoa/dregsy/

Thanks in advance for any answer :)

add support for a blacklist tag array

Sometimes you want to sync everything BUT a set of tags, this would be a great addition and I would think fairly quick to implement for someone who knows Go, sadly this person isn't me :(

    mappings:
      - from: repository/image
        to: repository/image
        blacklist-tags: ['some_tag', 'another_tag']

support token based authentication for Google Artifact Registry

We are getting issue while copying dockerhub images to google artifact registry repository (LOCATION-docker.pkg.dev)
as per documentation, it only address for Google Container Registry (GCR).
can we add support for google artifact registry repository similarly what we have for GCR
If we use GCP service account json key as auth described in here , we are getting following issue

INFO[0000] dregsy 0.3.6                                 
INFO[0000] skopeo version 1.2.1 commit: 1b6af3b15975f3142462b6affa85af708feb657f 
INFO[0000] relay ready                                   relay=skopeo
INFO[0000] syncing task                                  source=registry.hub.docker.com target=europe-west1-docker.pkg.dev task=dockerhub
INFO[0000] mapping                                       from=/library/alpine to=/<project-id>/upstream
INFO[0000] syncing tag                                   tag=3.10
DEBU[0008] Getting image source signatures              
DEBU[0012] time="2021-04-16T09:53:24Z" level=fatal msg="Error trying to reuse blob sha256:396c31837116ac290458afcb928f68b6cc1c7bdd6963fc72f52f365a2a89c1b5 at destination: Requesting bear token: invalid status code from registry 400 (Bad Request)" 
ERRO[0012] exit status 1                    

invalid character '_' looking for beginning of value

I am trying to dregsy image & skopeo relay for copying dockerhub image to google artifact registry repository but seeing following error

time="2021-04-15T07:54:53Z" level=error msg="invalid character '_' looking for beginning of value"

following is config.yaml file

relay: skopeo

# relay config sections
skopeo:
  binary: skopeo
  certs-dir: /etc/skopeo/certs.d

# list of sync tasks
tasks:

  - name: task1 # required
    interval: 60
    verbose: true
    source:
      registry: registry.hub.docker.com
      auth: <dockerhub_auth>
      lister:
        type: dockerhub
    target:
      registry: <google_artifact_registry_URL>
      auth: none
      skip-tls-verify: false
    mappings:
      - from: regex:xelalex/dregsy.*
        to: test/upstream/dregsy
        tags: ['master', 'latest']

Any help much appreciated

Add unit & e2e tests

There currently are no tests in dregsy. It still gets tested indirectly though, since I use it in a larger project and that project's testing would at least catch major flaws in dregsy. However, a meaningful test set is definitely needed, in particular for proceeding with new feature implementation & refactorings.

remove Skopeo submodule

The Skopeo project is phasing out static builds, so the previous approach of building a FROM scratch image for dregsy with just the two binaries no longer works. Instead, we should move to something like Alpine as the base, and install Skopeo via package management during image build.

Retire docker relay?

The docker relay seems to be much less efficient than the skopeo one. Syncing large registries involve downloading all tags locally first - which might take quite some space. Since the relay implementations are quite different, it makes adding new features more challenging. Is there an advantage in using the docker relay vs the Skopeo one? How about sunsetting it?

Can't use ECR without auth-refresh

The documentation implies auth-refresh is an optional feature for ECR registries, but if I use a configuration that does not have auth-refresh set, dregsy still tries to refresh credentials at start up, which doesn't work.

The reason I don't want auth-refresh is that I need separate credentials for source and target registries. Ideally, I would be able to specify a different AWS SDK auth profile for each, but for now, I simply wanted to use my hardcoded credentials without any attempt to refresh them.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.