2 changed files with 361 additions and 0 deletions
@ -0,0 +1,354 @@ |
|||
# Using Skopeo to copy docker images between registries |
|||
|
|||
## Context |
|||
|
|||
When you need to deploy a container in OpenShift, you need an image of |
|||
this container. This image can be built from scratch or from another |
|||
image or be available "off-the-shelf" in another registry. |
|||
|
|||
To use an image, three options are possible: |
|||
|
|||
1. reference the target image directly in the build / deployment |
|||
2. use an image stream that references the target image |
|||
3. copy the target image to the OpenShift registry |
|||
|
|||
Each approach as pros and cons. |
|||
|
|||
If you reference the target image directly in the build / deployment, |
|||
any change to the reference will be cumbersome to implement. For instance, |
|||
if you want to change all `centos:7.4` images by a `centos:7.5`, it will |
|||
require a lot of work. |
|||
|
|||
The [Image Stream](https://docs.openshift.com/container-platform/latest/dev_guide/managing_images.html) |
|||
is an indirection level that let you manage your images in a more flexible |
|||
way. An Image Stream contains tags and each tag can be: |
|||
|
|||
- a reference to an external image such as `docker.io/centos:7` or |
|||
`registry.access.redhat.com/rhel7:7.5`. |
|||
- a reference to another tag in the same image stream |
|||
- a reference to a tag in another image stream |
|||
- a container image by itself |
|||
|
|||
A reference can be used to point to an existing image which is fetched |
|||
directly by the OpenShift nodes when this image is needed (the pointed |
|||
image is not "mirrored" in the OpenShift registry). |
|||
|
|||
Alternatively, it is possible to copy physically the image to the |
|||
OpenShift registry. In this way, if the external registry is unavailable, |
|||
the image can still be fetched from within the OpenShift cluster. |
|||
|
|||
Also, some OpenShift clusters are completely disconnected from any other |
|||
network and copying images in the OpenShift registry is the only way to |
|||
use an image. |
|||
|
|||
In this document, we will see how to copy images between registries using |
|||
[skopeo](https://github.com/projectatomic/skopeo). |
|||
|
|||
## Installing skopeo |
|||
|
|||
Skopeo is available in RHEL, Fedora and CentOS as an RPM package: |
|||
|
|||
```sh |
|||
yum install skopeo |
|||
``` |
|||
|
|||
## Copying locally an image from DockerHub |
|||
|
|||
Let's say, we need to make a local copy of the `centos:7`, `centos:7.5.1804`, |
|||
`centos:7.4.1708` and `rhel7:7.5` images. |
|||
|
|||
First, you can inspect the target images using `skopeo inspect`: |
|||
|
|||
```sh |
|||
skopeo inspect docker://docker.io/centos:7 |
|||
skopeo inspect docker://docker.io/centos:7.5.1804 |
|||
skopeo inspect docker://docker.io/centos:7.4.1708 |
|||
``` |
|||
|
|||
The RHEL 7.5 image is hosted on a different registry (`registry.access.redhat.com`) |
|||
and needs to be fetched from a system registered on RHN/Satellite with the proper subscriptions. |
|||
|
|||
First, make sure you are on a RHEL system: |
|||
|
|||
```raw |
|||
$ cat /etc/redhat-release |
|||
Red Hat Enterprise Linux Server release 7.4 (Maipo) |
|||
``` |
|||
|
|||
Make sure the system is registered with RHN/Satellite: |
|||
|
|||
```raw |
|||
$ sudo subscription-manager status |
|||
+-------------------------------------------+ |
|||
System Status Details |
|||
+-------------------------------------------+ |
|||
Overall Status: Current |
|||
``` |
|||
|
|||
And then run the `skopeo inspect` as root: |
|||
|
|||
```sh |
|||
sudo skopeo inspect docker://registry.access.redhat.com/rhel7:7.5 |
|||
``` |
|||
|
|||
The `skopeo inspect` command queries information about the image |
|||
from the remote registry and prints them as JSON. If needed, you can then |
|||
extract the relevant fields using [jq](https://stedolan.github.io/jq/). |
|||
|
|||
Now that you inspected the desired images, you can copy them locally: |
|||
|
|||
```sh |
|||
skopeo copy docker://docker.io/centos:7 oci:./target:centos:7 |
|||
skopeo copy docker://docker.io/centos:7.5.1804 oci:./target:centos:7.5.1804 |
|||
skopeo copy docker://docker.io/centos:7.4.1708 oci:./target:centos:7.4.1708 |
|||
sudo skopeo copy docker://registry.access.redhat.com/rhel7:7.5 oci:./target:rhel7:7.5 |
|||
``` |
|||
|
|||
**Note:** we used `sudo` for the last command since we need to authenticate |
|||
to the Red Hat Registry with the machine credentials (the ones stored in |
|||
`/etc/docker/certs.d/registry.access.redhat.com`). |
|||
|
|||
The image have been copied locally, in a directory named `./target`. This |
|||
directory is in the OCI format (Open Container Initiative). |
|||
|
|||
You can inspect the local copy of those images with: |
|||
|
|||
```sh |
|||
skopeo inspect oci:./target:centos:7 |
|||
skopeo inspect oci:./target:centos:7.5.1804 |
|||
skopeo inspect oci:./target:centos:7.4.1708 |
|||
skopeo inspect oci:./target:rhel7:7.5 |
|||
``` |
|||
|
|||
## Accessing the OpenShift registry with `skopeo` |
|||
|
|||
To access the OpenShift registry, we need to: |
|||
|
|||
- find the URL of the registry |
|||
- create a service account |
|||
- give the proper privileges to this service account in order to pull or push |
|||
to the registry |
|||
|
|||
First, you can find the **public URL** of the registry by login as `cluster-admin` |
|||
on your OpenShit cluster and querying: |
|||
|
|||
```sh |
|||
oc get route docker-registry -n default -o 'jsonpath={.spec.host}{"\n"}' |
|||
``` |
|||
|
|||
If you are logged in on a node of your cluster, you can also reach the |
|||
OpenShift registry by its **private URL**: |
|||
|
|||
```sh |
|||
docker-registry.default.svc.cluster.local:5000 |
|||
``` |
|||
|
|||
In the rest of this guide, the registry URL will be replaced by an environment |
|||
variable named `REGISTRY`. |
|||
|
|||
If you are on one of your openshift nodes, you can use the internal URL: |
|||
|
|||
```sh |
|||
REGISTRY=docker-registry.default.svc.cluster.local:5000 |
|||
``` |
|||
|
|||
Otherwise, you can use the public URL: |
|||
|
|||
```sh |
|||
REGISTRY="$(oc get route docker-registry -n default -o 'jsonpath={.spec.host}')" |
|||
``` |
|||
|
|||
Then, create a project (or re-use an existing one) to hold the `skopeo` |
|||
service account: |
|||
|
|||
```sh |
|||
oc new-project admin |
|||
``` |
|||
|
|||
And create the service account: |
|||
|
|||
```sh |
|||
oc create serviceaccount skopeo |
|||
``` |
|||
|
|||
Extract the token of the `skopeo` service account: |
|||
|
|||
```sh |
|||
oc get secrets -o jsonpath='{range .items[?(@.metadata.annotations.kubernetes\.io/service-account\.name=="skopeo")]}{.metadata.annotations.openshift\.io/token-secret\.value}{end}' |tee skopeo-token |
|||
``` |
|||
|
|||
For the rest of this guide, the token will be replaced by an environment variable named `TOKEN`. |
|||
|
|||
You can set it using: |
|||
|
|||
```sh |
|||
TOKEN="$(cat skopeo-token)" |
|||
``` |
|||
|
|||
You can check that this token is working properly by inspecting an image stream |
|||
in the `openshift` namespace: |
|||
|
|||
```sh |
|||
skopeo --insecure-policy inspect --creds="skopeo:$TOKEN" docker://$REGISTRY/openshift/nodejs |
|||
``` |
|||
|
|||
`nodejs` is an image stream that is provisioned by default on every OpenShift |
|||
cluster. If it is not there on yours, you can pick any image stream in the |
|||
`openshift` namespace: |
|||
|
|||
```sh |
|||
oc get is -n openshift |
|||
``` |
|||
|
|||
## Pushing an image to the OpenShift registry |
|||
|
|||
If you want to push an image in the OpenShift registry, you will have to: |
|||
|
|||
- create a project to hold the pushed images |
|||
- grant the right to push images in this project to the `skopeo` service |
|||
account |
|||
|
|||
First, create a new project (or re-use an existing one) to hold the images |
|||
that you will push: |
|||
|
|||
```sh |
|||
oc new-project my-images |
|||
``` |
|||
|
|||
And then grant the right to push images in the `my-images` project to the |
|||
`skopeo` service account (that has been defined in the `admin` project): |
|||
|
|||
```sh |
|||
oc adm policy add-role-to-user system:image-builder -n my-images system:serviceaccount:admin:skopeo |
|||
``` |
|||
|
|||
You can then copy your images to the OpenShift registry, in the `my-images` |
|||
project: |
|||
|
|||
```sh |
|||
skopeo --insecure-policy copy --dest-creds="skopeo:$TOKEN" oci:./target:rhel7:7.5 docker://$REGISTRY/my-images/rhel7:7.5 |
|||
``` |
|||
|
|||
Did you know that even if you can store the images locally, you can also copy |
|||
them "on the fly" without any local storage ? |
|||
|
|||
Try to copy an image from the Docker Hub directly to the OpenShift registry: |
|||
|
|||
```sh |
|||
skopeo --insecure-policy copy --dest-creds="skopeo:$TOKEN" docker://docker.io/centos:7 docker://$REGISTRY/my-images/centos:7 |
|||
``` |
|||
|
|||
## Pulling an image to the OpenShift registry |
|||
|
|||
If you want to pull an image from the OpenShift registry, you will have to: |
|||
|
|||
- have access to the project that hold the images |
|||
- grant the right to pull images in this project to the `skopeo` service |
|||
account |
|||
|
|||
First, make sure you have access to the project that holds the images |
|||
(in this example, the project is named `other-images`): |
|||
|
|||
```sh |
|||
oc get imagestream -n other-images |
|||
``` |
|||
|
|||
And then grant the right to pull images from the `other-images` project to the |
|||
`skopeo` service account (that has been defined in the `admin` project): |
|||
|
|||
```sh |
|||
oc adm policy add-role-to-user system:image-puller -n other-images system:serviceaccount:admin:skopeo |
|||
``` |
|||
|
|||
You can then copy your images from the OpenShift registry, located in the |
|||
`other-images` project: |
|||
|
|||
```sh |
|||
skopeo --insecure-policy copy --src-creds="skopeo:$TOKEN" docker://$REGISTRY/other-images/myimage:latest oci:./target:myimage:latest |
|||
``` |
|||
|
|||
## Persist the registry credentials |
|||
|
|||
Instead of passing the registry credentials on the command line, you can store |
|||
them in a configuration file. |
|||
|
|||
Skopeo can re-use out-of-the-box any credential defined in the Docker/CRI-O |
|||
configuration. |
|||
|
|||
If you have Docker installed locally, you can login to the registry: |
|||
|
|||
```sh |
|||
docker login -u skopeo -p "$TOKEN" "$REGISTRY" |
|||
``` |
|||
|
|||
**Note:** to use the docker login, you need to be root or member of the |
|||
`docker` group. |
|||
|
|||
If you do not have docker installed locally or if you are neither root nor |
|||
member of the `docker` group, you can generate a Docker configuration |
|||
manually: |
|||
|
|||
```sh |
|||
mkdir -p $HOME/.docker |
|||
m4 "-D__REGISTRY__=$REGISTRY" "-D__BASE64AUTH__=$(echo -n "skopeo:$TOKEN" |base64 -w0)" < config.json.m4 > $HOME/.docker/config.json |
|||
chmod 600 $HOME/.docker/config.json |
|||
``` |
|||
|
|||
Try to inspect an image from the OpenShift registry without any explicit |
|||
credentials: |
|||
|
|||
```sh |
|||
skopeo inspect docker://$REGISTRY/openshift/nodejs:latest |
|||
``` |
|||
|
|||
## SSL/TLS issues |
|||
|
|||
If you are using skopeo from a machine that is not part of the cluster, |
|||
you will have to trust the OpenShift CA Certificate on this machine. |
|||
|
|||
Otherwise, you will get an SSL/TLS Certificate Validation error: |
|||
|
|||
```sh |
|||
FATA[0000] pinging docker registry returned: Get https://docker-registry-default.app.itix.fr/v2/: x509: certificate signed by unknown authority |
|||
``` |
|||
|
|||
If you need to trust the OpenShift CA, you will have to: |
|||
|
|||
- fetch it from the master |
|||
- store it in your CA Trust Store |
|||
- update the CA Trust Store |
|||
|
|||
You can fetch the OpenShift CA certificate by using `openssl s_client` to |
|||
connect to the master: |
|||
|
|||
```sh |
|||
openssl s_client -host openshift.itix.fr -port 8443 -showcerts > trace < /dev/null |
|||
perl -0777 -ne 'while (m|((-----BEGIN CERTIFICATE-----)[-A-Za-z0-9+/=\n]+(-----END CERTIFICATE-----))|igs) { $cert = $1 }; print $cert, "\n";' > openshift-ca.crt |
|||
``` |
|||
|
|||
You can check that the fetched certificate is correct with: |
|||
|
|||
```sh |
|||
cat openshift-ca.crt |
|||
openssl x509 -noout -text -in openshift-ca.crt |
|||
``` |
|||
|
|||
If it is correct, you can copy the CA certificate in the CA Trust Store: |
|||
|
|||
```sh |
|||
sudo cp openshift-ca.crt /etc/pki/ca-trust/source/anchors/skopeo-openshift-ca.crt |
|||
``` |
|||
|
|||
You can now update the CA Trust Store: |
|||
|
|||
```sh |
|||
sudo update-ca-trust extract |
|||
``` |
|||
|
|||
## Conclusion |
|||
|
|||
Skopeo is a powerful tool to copy and archive container images. It is |
|||
self-contained and does not depend on the Docker daemon. |
|||
|
|||
You can use it to copy images between registries, including the OpenShift |
|||
registry. |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"auths": { |
|||
"https://__REGISTRY__/v2/": { |
|||
"auth": "__BASE64AUTH__" |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue