├── talk-at-kcd-munich-2023.md ├── .gitignore ├── assets ├── quay-4eab20bcf7da.png ├── quay-76535c50cab1.png ├── quay-d3b7a48ede60.png ├── quay-4eab20bcf7da-hl.png ├── quay-76535c50cab1-hl.png └── quay-multi-arch-overview.png ├── setup-demo-env ├── hcloud.yaml ├── hosts.yaml ├── destroy-hcloud-instances.yaml ├── ansible-navigator.yaml ├── ansible.cfg └── create-hcloud-instances.yaml ├── Containerfile.windows ├── Containerfile ├── .tekton └── multi-arch.yaml ├── LICENSE └── README.md /talk-at-kcd-munich-2023.md: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | print-runtime-* 2 | ansible-navigator.log 3 | -------------------------------------------------------------------------------- /assets/quay-4eab20bcf7da.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-examples/multi-arch/HEAD/assets/quay-4eab20bcf7da.png -------------------------------------------------------------------------------- /assets/quay-76535c50cab1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-examples/multi-arch/HEAD/assets/quay-76535c50cab1.png -------------------------------------------------------------------------------- /assets/quay-d3b7a48ede60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-examples/multi-arch/HEAD/assets/quay-d3b7a48ede60.png -------------------------------------------------------------------------------- /assets/quay-4eab20bcf7da-hl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-examples/multi-arch/HEAD/assets/quay-4eab20bcf7da-hl.png -------------------------------------------------------------------------------- /assets/quay-76535c50cab1-hl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-examples/multi-arch/HEAD/assets/quay-76535c50cab1-hl.png -------------------------------------------------------------------------------- /setup-demo-env/hcloud.yaml: -------------------------------------------------------------------------------- 1 | plugin: hcloud 2 | token: "{{ lookup('ansible.builtin.env', 'HCLOUD_MULTI_ARCH_TOKEN') }}" 3 | 4 | -------------------------------------------------------------------------------- /Containerfile.windows: -------------------------------------------------------------------------------- 1 | ARG WINVER=ltsc2022 2 | FROM mcr.microsoft.com/windows/servercore:${WINVER} 3 | 4 | CMD echo Hello from Windows -------------------------------------------------------------------------------- /assets/quay-multi-arch-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-examples/multi-arch/HEAD/assets/quay-multi-arch-overview.png -------------------------------------------------------------------------------- /setup-demo-env/hosts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | laptop: 3 | hosts: 4 | laptop: 5 | ansible_host: 127.0.0.1 6 | ansible_user: rbohne 7 | -------------------------------------------------------------------------------- /Containerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi9/ubi-micro AS runner 2 | 3 | # Run a command, to have an architecture-specific action during the build 4 | RUN uname -om 5 | 6 | CMD ["uname","-om" ] 7 | -------------------------------------------------------------------------------- /setup-demo-env/destroy-hcloud-instances.yaml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ansible-playbook 2 | --- 3 | - name: Destroy all hcloud_instance 4 | hosts: hcloud 5 | gather_facts: no 6 | tasks: 7 | - name: "Destroy {{ name }}" 8 | hcloud_server: 9 | api_token: "{{ lookup('ansible.builtin.env', 'HCLOUD_MULTI_ARCH_TOKEN') }}" 10 | name: "{{ name }}" 11 | state: absent 12 | -------------------------------------------------------------------------------- /setup-demo-env/ansible-navigator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible-navigator: 3 | ansible: 4 | inventory: 5 | entries: 6 | - hcloud.yaml 7 | - hosts.yaml 8 | execution-environment: 9 | container-options: 10 | - --net=host 11 | environment-variables: 12 | pass: 13 | - HCLOUD_MULTI_ARCH_TOKEN 14 | image: quay.io/rbohne/lab-ee:latest 15 | logging: 16 | level: info 17 | mode: stdout 18 | playbook-artifact: 19 | enable: false 20 | -------------------------------------------------------------------------------- /setup-demo-env/ansible.cfg: -------------------------------------------------------------------------------- 1 | # config file for ansible -- http://ansible.com/ 2 | # ============================================== 3 | 4 | # This config file provides examples for running 5 | # the OpenShift playbooks with the provided 6 | # inventory scripts. 7 | 8 | [defaults] 9 | # Set the log_path 10 | log_path = ~/ansible.log 11 | 12 | # Additional default options for OpenShift Ansible 13 | forks = 20 14 | host_key_checking = False 15 | retry_files_enabled = False 16 | retry_files_save_path = ~/ansible-installer-retries 17 | nocows = True 18 | remote_user = root 19 | # roles_path = roles/ 20 | gathering = smart 21 | # fact_caching = jsonfile 22 | # fact_caching_connection = $HOME/ansible/facts 23 | # fact_caching_timeout = 600 24 | callbacks_enabled = profile_tasks 25 | # callbacks_enabled 26 | inventory_ignore_extensions = secrets.py, .pyc, .cfg, .crt, .ini 27 | # work around privilege escalation timeouts in ansible: 28 | timeout = 30 29 | 30 | # Uncomment to use the provided example inventory 31 | inventory = hosts.yaml 32 | 33 | ansible_python_interpreter = auto 34 | 35 | # Additional ssh options for OpenShift Ansible 36 | [ssh_connection] 37 | pipelining = True 38 | ssh_args = -o ControlMaster=auto -o ControlPersist=600s 39 | timeout = 10 40 | # shorten the ControlPath which is often too long; when it is, 41 | # ssh connection reuse silently fails, making everything slower. 42 | control_path = %(directory)s/%%h-%%r -------------------------------------------------------------------------------- /setup-demo-env/create-hcloud-instances.yaml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ansible-playbook 2 | --- 3 | - name: Start hcloud_instance 4 | hosts: laptop 5 | gather_facts: no 6 | tasks: 7 | - name: Create arm-instance 8 | delegate_to: localhost 9 | hetzner.hcloud.hcloud_server: 10 | api_token: "{{ lookup('ansible.builtin.env', 'HCLOUD_MULTI_ARCH_TOKEN') }}" 11 | name: arm-instance 12 | server_type: cax11 13 | image: fedora-38 14 | location: fsn1 15 | state: present 16 | enable_ipv6: false 17 | ssh_keys: 18 | - rbohne@redhat.com 19 | register: output 20 | 21 | - name: Update ~/.ssh/config 22 | blockinfile: 23 | path: ~/.ssh/config 24 | marker: "# {mark} - multi-arch arm-instance " 25 | block: | 26 | Host arm-instance 27 | HostName {{ output.hcloud_server.ipv4_address }} 28 | User root 29 | 30 | - name: Wait 300 seconds for port 22 to become open 31 | delegate_to: localhost 32 | ansible.builtin.wait_for: 33 | port: 22 34 | host: '{{ output.hcloud_server.ipv4_address }}' 35 | delay: 1 36 | timeout: 300 37 | connection: local 38 | 39 | - name: Create x86-instance 40 | delegate_to: localhost 41 | hetzner.hcloud.hcloud_server: 42 | api_token: "{{ lookup('ansible.builtin.env', 'HCLOUD_MULTI_ARCH_TOKEN') }}" 43 | name: x86-instance 44 | server_type: cx11 45 | image: fedora-38 46 | location: fsn1 47 | state: present 48 | enable_ipv6: false 49 | ssh_keys: 50 | - rbohne@redhat.com 51 | register: output 52 | 53 | - name: Update ~/.ssh/config 54 | blockinfile: 55 | path: ~/.ssh/config 56 | marker: "# {mark} - multi-arch x86-instance " 57 | block: | 58 | Host x86-instance 59 | HostName {{ output.hcloud_server.ipv4_address }} 60 | User root 61 | 62 | - name: Wait 300 seconds for port 22 to become open 63 | delegate_to: localhost 64 | ansible.builtin.wait_for: 65 | port: 22 66 | host: '{{ output.hcloud_server.ipv4_address }}' 67 | delay: 1 68 | timeout: 300 69 | connection: local 70 | 71 | - name: refresh_inventory 72 | ansible.builtin.meta: refresh_inventory 73 | 74 | - name: Install packages 75 | hosts: hcloud 76 | gather_facts: no 77 | tasks: 78 | # sudo dnf install podman skopeo buildah jq git tmux 79 | - name: Install packages 80 | ansible.builtin.dnf: 81 | name: 82 | - podman 83 | - skopeo 84 | - buildah 85 | - jq 86 | - git 87 | - tmux 88 | state: latest 89 | # git clone https://github.com/openshift-examples/multi-arch.git 90 | - name: Clone demo repo 91 | ansible.builtin.git: 92 | repo: https://github.com/openshift-examples/multi-arch.git 93 | dest: /root/multi-arch 94 | -------------------------------------------------------------------------------- /.tekton/multi-arch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: PipelineRun 3 | metadata: 4 | name: multi-arch 5 | 6 | labels: 7 | tekton.dev/pipeline: multi-arch 8 | annotations: 9 | pipelinesascode.tekton.dev/on-event: "[push]" 10 | # The branch or tag we are targeting (ie: main, refs/tags/*) 11 | pipelinesascode.tekton.dev/on-target-branch: "[main,devel]" 12 | 13 | pipelinesascode.tekton.dev/task: "git-clone" 14 | pipelinesascode.tekton.dev/task-1: "buildah" 15 | 16 | # Use maven task from hub 17 | # pipelinesascode.tekton.dev/task-1: "[pre-commit]" 18 | 19 | # You can add more tasks in here to reuse, browse the one you like from here 20 | # https://hub.tekton.dev/ 21 | # example: 22 | # pipelinesascode.tekton.dev/task-2: "[.tekton/task/github-add-labels.yaml]" 23 | # pipelinesascode.tekton.dev/task-3: "[.tekton/task/github-add-comment.yaml]" 24 | 25 | # How many runs we want to keep attached to this event 26 | pipelinesascode.tekton.dev/max-keep-runs: "1" 27 | 28 | spec: 29 | params: 30 | 31 | taskRunSpecs: 32 | # Build the amd64 image on dedicated amd64 hardware 33 | - pipelineTaskName: build-on-amd64 34 | taskPodTemplate: 35 | nodeSelector: 36 | kubernetes.io/arch: amd64 37 | # Build the arm64 image on dedicated arm64 hardware 38 | - pipelineTaskName: build-on-arm64 39 | taskPodTemplate: 40 | nodeSelector: 41 | kubernetes.io/arch: arm64 42 | 43 | pipelineSpec: 44 | params: 45 | #- name: repo_url 46 | #- name: revision 47 | workspaces: 48 | - name: source 49 | - name: push-secret 50 | tasks: 51 | - name: git-clone 52 | params: 53 | - name: url 54 | value: 'https://github.com/openshift-examples/multi-arch.git' 55 | - name: revision 56 | value: main 57 | taskRef: 58 | kind: ClusterTask 59 | name: git-clone 60 | workspaces: 61 | - name: output 62 | workspace: source 63 | 64 | - name: build-on-arm64 65 | params: 66 | - name: IMAGE 67 | value: 'quay.io/openshift-examples/multi-arch:pac-arm64' 68 | - name: DOCKERFILE 69 | value: ./Containerfile 70 | runAfter: 71 | - git-clone 72 | taskRef: 73 | kind: ClusterTask 74 | name: buildah 75 | workspaces: 76 | - name: source 77 | workspace: source 78 | - name: dockerconfig 79 | workspace: push-secret 80 | 81 | - name: build-on-amd64 82 | params: 83 | - name: IMAGE 84 | value: 'quay.io/openshift-examples/multi-arch:pac-amd64' 85 | - name: DOCKERFILE 86 | value: ./Containerfile 87 | runAfter: 88 | - build-on-arm64 89 | taskRef: 90 | kind: ClusterTask 91 | name: buildah 92 | workspaces: 93 | - name: source 94 | workspace: source 95 | - name: dockerconfig 96 | workspace: push-secret 97 | 98 | - name: create-and-push-manifest 99 | runAfter: 100 | - build-on-amd64 101 | params: 102 | - name: IMAGE 103 | value: 'quay.io/openshift-examples/multi-arch:pac' 104 | - name: IMAGE_URL_AMD64 105 | value: $(tasks.build-on-amd64.results.IMAGE_URL) 106 | - name: IMAGE_URL_ARM64 107 | value: $(tasks.build-on-arm64.results.IMAGE_URL) 108 | workspaces: 109 | - name: source 110 | workspace: source 111 | - name: dockerconfig 112 | workspace: push-secret 113 | taskSpec: 114 | volumes: 115 | - emptyDir: {} 116 | name: varlibcontainers 117 | workspaces: 118 | - name: source 119 | - description: >- 120 | An optional workspace that allows providing a .docker/config.json file 121 | for Buildah to access the container registry. The file should be placed 122 | at the root of the Workspace with name config.json or .dockerconfigjson. 123 | name: dockerconfig 124 | optional: true 125 | params: 126 | - description: Reference of the image buildah will produce. 127 | name: IMAGE 128 | type: string 129 | - default: >- 130 | registry.redhat.io/rhel8/buildah@sha256:00795fafdab9bbaa22cd29d1faa1a01e604e4884a2c935c1bf8e3d1f0ad1c084 131 | description: The location of the buildah builder image. 132 | name: BUILDER_IMAGE 133 | type: string 134 | - name: IMAGE_URL_AMD64 135 | type: string 136 | - name: IMAGE_URL_ARM64 137 | type: string 138 | steps: 139 | - name: create-and-push 140 | image: $(params.BUILDER_IMAGE) 141 | env: 142 | - name: IMAGE_URL_AMD64 143 | value: $(params.IMAGE_URL_AMD64) 144 | - name: IMAGE_URL_ARM64 145 | value: $(params.IMAGE_URL_ARM64) 146 | securityContext: 147 | capabilities: 148 | add: 149 | - SETFCAP 150 | volumeMounts: 151 | - mountPath: /var/lib/containers 152 | name: varlibcontainers 153 | workingDir: $(workspaces.source.path) 154 | script: | 155 | if [[ "$(workspaces.dockerconfig.bound)" == "true" ]]; then 156 | 157 | # if config.json exists at workspace root, we use that 158 | if test -f "$(workspaces.dockerconfig.path)/config.json"; then 159 | export DOCKER_CONFIG="$(workspaces.dockerconfig.path)" 160 | 161 | # else we look for .dockerconfigjson at the root 162 | elif test -f "$(workspaces.dockerconfig.path)/.dockerconfigjson"; then 163 | cp "$(workspaces.dockerconfig.path)/.dockerconfigjson" "$HOME/.docker/config.json" 164 | export DOCKER_CONFIG="$HOME/.docker" 165 | 166 | # need to error out if neither files are present 167 | else 168 | echo "neither 'config.json' nor '.dockerconfigjson' found at workspace root" 169 | exit 1 170 | fi 171 | fi 172 | set -x 173 | buildah manifest create localhost/list 174 | buildah manifest add localhost/list $IMAGE_URL_AMD64 175 | buildah manifest add localhost/list $IMAGE_URL_ARM64 176 | buildah manifest push localhost/list docker://$(params.IMAGE) 177 | 178 | workspaces: 179 | - name: source 180 | volumeClaimTemplate: 181 | metadata: 182 | creationTimestamp: null 183 | spec: 184 | accessModes: 185 | - ReadWriteOnce 186 | resources: 187 | requests: 188 | storage: 1Gi 189 | volumeMode: Filesystem 190 | - name: push-secret 191 | secret: 192 | secretName: quay-push-bot 193 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Demystifying Container Images: Unveiling the Secrets of Multi-Architecture, Manifests, IDs, and Digests 2 | 3 | ## Build container image (amd64/x86_64) 4 | 5 | ```bash 6 | [root@x86-instance multi-arch]# buildah bud -f Containerfile \ 7 | -t quay.io/openshift-examples/multi-arch:demo-$(uname -m) . 8 | STEP 1/2: FROM registry.access.redhat.com/ubi9/ubi-micro AS runner 9 | Trying to pull registry.access.redhat.com/ubi9/ubi-micro:latest... 10 | Getting image source signatures 11 | Checking if image destination supports signatures 12 | Copying blob 9e167103aefa done 13 | Copying config 1b9d4f56fb done 14 | Writing manifest to image destination 15 | Storing signatures 16 | STEP 2/2: CMD ["uname","-om" ] 17 | COMMIT quay.io/openshift-examples/multi-arch:demo-x86_64 18 | Getting image source signatures 19 | Copying blob a3ede86005c1 skipped: already exists 20 | Copying blob 5f70bf18a086 done 21 | Copying config 81b91103bc done 22 | Writing manifest to image destination 23 | --> 81b91103bcad 24 | Successfully tagged quay.io/openshift-examples/multi-arch:demo-x86_64 25 | 81b91103bcad946edabad074db3e3eefcbfccd307587b6b40257bb0932a31705 26 | ``` 27 | 28 | List images (not pushed, yet) 29 | ``` 30 | [root@x86-instance multi-arch]# podman images --digests --no-trunc 31 | REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE 32 | quay.io/openshift-examples/multi-arch demo-x86_64 sha256:66ade3f15bca773a0227d4ff479bb1191b5e5bb94da88bab7307284129bb1733 sha256:81b91103bcad946edabad074db3e3eefcbfccd307587b6b40257bb0932a31705 28 seconds ago 26.1 MB 33 | registry.access.redhat.com/ubi9/ubi-micro latest sha256:bd93cff066cc579e49d53f50782f7edad319031e9d511b1e8709cf16be8d78a0 sha256:1b9d4f56fb2cd4401fa14437e3f245e6872388ed3e50f72926234315cbf4f817 3 weeks ago 26.1 MB 34 | ``` 35 | 36 |
37 | Discover image details - Manifest (`sha256:66ade3f15bca`) 38 | 39 | ### Discover image details - Manifest (`sha256:66ade3f15bca`) 40 | 41 | ```bash 42 | # Get Digest 43 | [root@x86-instance multi-arch]# skopeo inspect --raw containers-storage:quay.io/openshift-examples/multi-arch:demo-$(uname -m) | sha256sum 44 | INFO[0000] Not using native diff for overlay, this may cause degraded performance for building images: kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled 45 | 66ade3f15bca773a0227d4ff479bb1191b5e5bb94da88bab7307284129bb1733 - 46 | ``` 47 | 48 | ```json 49 | { 50 | "schemaVersion": 2, 51 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 52 | "config": { 53 | "mediaType": "application/vnd.oci.image.config.v1+json", 54 | "digest": "sha256:81b91103bcad946edabad074db3e3eefcbfccd307587b6b40257bb0932a31705", 55 | "size": 4245 56 | }, 57 | "layers": [ 58 | { 59 | "mediaType": "application/vnd.oci.image.layer.v1.tar", 60 | "digest": "sha256:a3ede86005c19f841273a0c4b8ee64628a029794025b7274cb8cbd4c9d2c6e11", 61 | "size": 26085888 62 | }, 63 | { 64 | "mediaType": "application/vnd.oci.image.layer.v1.tar", 65 | "digest": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", 66 | "size": 1024 67 | } 68 | ], 69 | "annotations": { 70 | "org.opencontainers.image.base.digest": "sha256:a54f5a7a9b67f32b6ae402cf0659ba4a3fd8eed4bdcbd00b5514ce4450b31214", 71 | "org.opencontainers.image.base.name": "registry.access.redhat.com/ubi9/ubi-micro:latest" 72 | } 73 | } 74 | ``` 75 |
76 | 77 |
78 | Discover image details - Config (`sha256:81b91103bcad`) 79 | 80 | ### Discover image details - Config (`sha256:81b91103bcad`) 81 | 82 | ```bash 83 | # Get ImageID 84 | [root@x86-instance multi-arch]# skopeo inspect --raw containers-storage:quay.io/openshift-examples/multi-arch:demo-$(uname -m) | jq '.config.digest' 85 | INFO[0000] Not using native diff for overlay, this may cause degraded performance for building images: kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled 86 | "sha256:81b91103bcad946edabad074db3e3eefcbfccd307587b6b40257bb0932a31705" 87 | [root@x86-instance multi-arch]# 88 | ``` 89 | 90 | `skopeo inspect --config containers-storage:quay.io/openshift-examples/multi-arch:demo-$(uname -m)`: 91 | ```json 92 | { 93 | "created": "2023-10-01T19:27:45.860244628Z", 94 | "architecture": "amd64", 95 | "os": "linux", 96 | "config": { 97 | "Env": [ 98 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 99 | ], 100 | "Cmd": [ 101 | "uname", 102 | "-om" 103 | ], 104 | "Labels": { 105 | [...snipped...] 106 | } 107 | }, 108 | "rootfs": { 109 | "type": "layers", 110 | "diff_ids": [ 111 | "sha256:a3ede86005c19f841273a0c4b8ee64628a029794025b7274cb8cbd4c9d2c6e11", 112 | "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" 113 | ] 114 | } 115 | "history": [ 116 | [...snipped...] 117 | ] 118 | } 119 | ``` 120 |
121 | 122 | ## Push container image (amd64/x86_64) 123 | 124 | ``` 125 | [root@x86-instance multi-arch]# podman push quay.io/openshift-examples/multi-arch:demo-$(uname -m) 126 | Getting image source signatures 127 | Copying blob 5f70bf18a086 done | 128 | Copying blob a3ede86005c1 done | 129 | Copying config 81b91103bc done | 130 | Writing manifest to image destination 131 | ``` 132 | 133 | ![quay-76535c50cab1-hl.png](assets/quay-76535c50cab1-hl.png) 134 | 135 | 136 | ## 😱 Different digest 137 | 138 | 139 | ```bash 140 | # Get Manifest from local image 141 | [root@x86-instance multi-arch]# skopeo inspect --raw containers-storage:quay.io/openshift-examples/multi-arch:demo-$(uname -m) > 66ade3f15bca.json 142 | INFO[0000] Not using native diff for overlay, this may cause degraded performance for building images: kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled 143 | 144 | # Get Manifest from image in container registry 145 | [root@x86-instance multi-arch]# skopeo inspect --raw docker://quay.io/openshift-examples/multi-arch:demo-$(uname -m) > 76535c50cab1.json 146 | 147 | # Double check sha256sum 148 | [root@x86-instance multi-arch]# sha256sum *json 149 | 66ade3f15bca773a0227d4ff479bb1191b5e5bb94da88bab7307284129bb1733 66ade3f15bca.json 150 | 76535c50cab1708ff17dc67e93d2a06dea01978f7201d17fd6b28b32f8ce9555 76535c50cab1.json 151 | 152 | # "Cleanup" json 153 | [root@x86-instance multi-arch]# jq . 66ade3f15bca.json > 66ade3f15bca.pretty.json 154 | [root@x86-instance multi-arch]# jq . 76535c50cab1.json > 76535c50cab1.pretty.json 155 | 156 | # Diff 157 | [root@x86-instance multi-arch]# diff -Nuar 66ade3f15bca.pretty.json 76535c50cab1.pretty.json 158 | ``` 159 | ```diff 160 | --- 66ade3f15bca.pretty.json 2023-10-01 19:41:38.331150221 +0000 161 | +++ 76535c50cab1.pretty.json 2023-10-01 19:41:46.923176546 +0000 162 | @@ -8,14 +8,14 @@ 163 | }, 164 | "layers": [ 165 | { 166 | - "mediaType": "application/vnd.oci.image.layer.v1.tar", 167 | - "digest": "sha256:a3ede86005c19f841273a0c4b8ee64628a029794025b7274cb8cbd4c9d2c6e11", 168 | - "size": 26085888 169 | + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 170 | + "digest": "sha256:9e167103aefa56af4c39359687f54fdd263ca85bc946e770d92c054df7ada57c", 171 | + "size": 7686605 172 | }, 173 | { 174 | - "mediaType": "application/vnd.oci.image.layer.v1.tar", 175 | - "digest": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", 176 | - "size": 1024 177 | + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 178 | + "digest": "sha256:bd9ddc54bea929a22b334e73e026d4136e5b73f5cc29942896c72e4ece69b13d", 179 | + "size": 34 180 | } 181 | ], 182 | "annotations": { 183 | ``` 184 | 185 | ## Build and Push container image (arm64/aarch64) 186 | 187 | 188 | ```bash 189 | [root@arm-instance multi-arch]# buildah bud -f Containerfile \ 190 | -t quay.io/openshift-examples/multi-arch:demo-$(uname -m) . 191 | STEP 1/2: FROM registry.access.redhat.com/ubi9/ubi-micro AS runner 192 | Trying to pull registry.access.redhat.com/ubi9/ubi-micro:latest... 193 | Getting image source signatures 194 | Checking if image destination supports signatures 195 | Copying blob 76f837f08b76 done 196 | Copying config 97f43b6789 done 197 | Writing manifest to image destination 198 | Storing signatures 199 | STEP 2/2: CMD ["uname","-om" ] 200 | COMMIT quay.io/openshift-examples/multi-arch:demo-aarch64 201 | Getting image source signatures 202 | Copying blob 791a6a33d694 skipped: already exists 203 | Copying blob 5f70bf18a086 done 204 | Copying config 01d89888b7 done 205 | Writing manifest to image destination 206 | --> 01d89888b7ef 207 | Successfully tagged quay.io/openshift-examples/multi-arch:demo-aarch64 208 | 01d89888b7ef4cb7709345dd8f5f9a9ee352007a613f2b41fed11571f6f53a95 209 | ``` 210 | 211 | List images (not pushed, yet) 212 | ``` 213 | [root@arm-instance multi-arch]# podman images --digests --no-trunc 214 | REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE 215 | quay.io/openshift-examples/multi-arch demo-aarch64 sha256:c3bb20ed9d0466c9234763764baab5b5ffd7bd87e5ca2459c889c5ddbe411fbe sha256:01d89888b7ef4cb7709345dd8f5f9a9ee352007a613f2b41fed11571f6f53a95 31 seconds ago 27.3 MB 216 | registry.access.redhat.com/ubi9/ubi-micro latest sha256:bd93cff066cc579e49d53f50782f7edad319031e9d511b1e8709cf16be8d78a0 sha256:97f43b6789e0162674e5fe274a3b39d4894062b4ec8e5b0c4f9305f43223c797 2 weeks ago 27.3 MB 217 | ``` 218 | 219 |
220 | Discover image details - Manifest (`sha256:c3bb20ed9d04`) 221 | 222 | ### Discover image details - Manifest (`sha256:c3bb20ed9d04`) 223 | 224 | ```bash 225 | # Get Digest 226 | [root@arm-instance multi-arch]# skopeo inspect --raw containers-storage:quay.io/openshift-examples/multi-arch:demo-$(uname -m) | sha256sum 227 | INFO[0000] Not using native diff for overlay, this may cause degraded performance for building images: kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled 228 | c3bb20ed9d0466c9234763764baab5b5ffd7bd87e5ca2459c889c5ddbe411fbe - 229 | ``` 230 | 231 | ```json 232 | { 233 | "schemaVersion": 2, 234 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 235 | "config": { 236 | "mediaType": "application/vnd.oci.image.config.v1+json", 237 | "digest": "sha256:01d89888b7ef4cb7709345dd8f5f9a9ee352007a613f2b41fed11571f6f53a95", 238 | "size": 4247 239 | }, 240 | "layers": [ 241 | { 242 | "mediaType": "application/vnd.oci.image.layer.v1.tar", 243 | "digest": "sha256:791a6a33d694bf7f1a8a1373b17e2cead2c0e2ee17620cd64128acfa88d2a953", 244 | "size": 27290112 245 | }, 246 | { 247 | "mediaType": "application/vnd.oci.image.layer.v1.tar", 248 | "digest": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", 249 | "size": 1024 250 | } 251 | ], 252 | "annotations": { 253 | "org.opencontainers.image.base.digest": "sha256:937f8e16fda9d9d2dceaa03870bf40d355ef68eea8faa04cd56cd59d6d33866a", 254 | "org.opencontainers.image.base.name": "registry.access.redhat.com/ubi9/ubi-micro:latest" 255 | } 256 | } 257 | ``` 258 |
259 | 260 |
261 | Discover image details - Config (`sha256:01d89888b7ef`) 262 | 263 | ### Discover image details - Config (`sha256:01d89888b7ef`) 264 | 265 | ```bash 266 | # Get ImageID 267 | [root@arm-instance multi-arch]# skopeo inspect --raw containers-storage:quay.io/openshift-examples/multi-arch:demo-$(uname -m) | jq '.config.digest' 268 | INFO[0000] Not using native diff for overlay, this may cause degraded performance for building images: kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled 269 | "sha256:01d89888b7ef4cb7709345dd8f5f9a9ee352007a613f2b41fed11571f6f53a95" 270 | ``` 271 | 272 | `skopeo inspect --config containers-storage:quay.io/openshift-examples/multi-arch:demo-$(uname -m)`: 273 | ```json 274 | { 275 | "created": "2023-07-14T11:49:23.062774594Z", 276 | "architecture": "amd64", 277 | "os": "linux", 278 | "config": { 279 | "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], 280 | "Cmd": ["uname","-om"], 281 | "Labels": { 282 | "architecture": "x86_64", 283 | "build-date": "2023-06-15T11:05:34", 284 | [...snipped...] 285 | } 286 | }, 287 | "rootfs": { 288 | "type": "layers", 289 | "diff_ids": [ 290 | "sha256:e54dc53d0edbbc96d3307fdea7bc1ed433d9083a1aab033dc3b38fd8b4fb165a", 291 | "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" 292 | ] 293 | }, 294 | "history": [ 295 | [...snipped...] 296 | ] 297 | } 298 | ``` 299 |
300 | 301 | ## Push container image (amd64/x86_64) 302 | 303 | ``` 304 | [root@arm-instance ~]# podman push quay.io/openshift-examples/multi-arch:demo-$(uname -m) 305 | Getting image source signatures 306 | Copying blob 791a6a33d694 done | 307 | Copying blob 5f70bf18a086 done | 308 | Copying config 01d89888b7 done | 309 | Writing manifest to image destination 310 | ``` 311 | 312 | ![quay-4eab20bcf7da-hl.png](assets/quay-4eab20bcf7da-hl.png) 313 | 314 | 315 | ## 😱 Different digest 316 | 317 | 318 | ```bash 319 | # Get Manifest from local image 320 | [root@arm-instance ~]# skopeo inspect --raw containers-storage:quay.io/openshift-examples/multi-arch:demo-$(uname -m) > c3bb20ed9d04.json 321 | INFO[0000] Not using native diff for overlay, this may cause degraded performance for building images: kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled 322 | 323 | # Get Manifest from image in container registry 324 | [root@arm-instance overlay]# skopeo inspect --raw docker://quay.io/openshift-examples/multi-arch:demo-$(uname -m) > 4eab20bcf7da.json 325 | 326 | # Double check sha256sum 327 | [root@arm-instance ~]# sha256sum *json 328 | 4eab20bcf7da10905cb95ce80141869e84854d15d99454e1365f10286d519f62 4eab20bcf7da.json 329 | c3bb20ed9d0466c9234763764baab5b5ffd7bd87e5ca2459c889c5ddbe411fbe c3bb20ed9d04.json 330 | 331 | # "Cleanup" json 332 | [root@arm-instance ~]# jq . 4eab20bcf7da.json > 4eab20bcf7da.pretty.json 333 | [root@arm-instance ~]# jq . c3bb20ed9d04.json > c3bb20ed9d04.pretty.json 334 | 335 | # Diff 336 | [root@arm-instance ~]# diff -Nuar 4eab20bcf7da.pretty.json c3bb20ed9d04.pretty.json 337 | ``` 338 | ```diff 339 | --- 4eab20bcf7da.pretty.json 2023-10-01 19:22:19.243175721 +0000 340 | +++ c3bb20ed9d04.pretty.json 2023-10-01 19:22:33.857304565 +0000 341 | @@ -8,14 +8,14 @@ 342 | }, 343 | "layers": [ 344 | { 345 | - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 346 | - "digest": "sha256:76f837f08b7667f5c10d53f91ca4885797a2cfa13f195e9bd024ad9ad934d0d2", 347 | - "size": 7099212 348 | + "mediaType": "application/vnd.oci.image.layer.v1.tar", 349 | + "digest": "sha256:791a6a33d694bf7f1a8a1373b17e2cead2c0e2ee17620cd64128acfa88d2a953", 350 | + "size": 27290112 351 | }, 352 | { 353 | - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 354 | - "digest": "sha256:bd9ddc54bea929a22b334e73e026d4136e5b73f5cc29942896c72e4ece69b13d", 355 | - "size": 34 356 | + "mediaType": "application/vnd.oci.image.layer.v1.tar", 357 | + "digest": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", 358 | + "size": 1024 359 | } 360 | ], 361 | "annotations": { 362 | ``` 363 | 364 | ## Create multi-arch image / fat-manifest 365 | 366 | ``` 367 | [root@x86-instance multi-arch]# podman manifest create localhost/demo 368 | 0deab136998a9b9143d5b253b1b6e8a6d741cfeb5fd9641379a4317ec117bc38 369 | [root@x86-instance multi-arch]# podman manifest add localhost/demo quay.io/openshift-examples/multi-arch:demo-x86_64 370 | 0deab136998a9b9143d5b253b1b6e8a6d741cfeb5fd9641379a4317ec117bc38 371 | [root@x86-instance multi-arch]# podman manifest add localhost/demo quay.io/openshift-examples/multi-arch:demo-aarch64 372 | 0deab136998a9b9143d5b253b1b6e8a6d741cfeb5fd9641379a4317ec117bc38 373 | [root@x86-instance multi-arch]# podman manifest push localhost/demo quay.io/openshift-examples/multi-arch:demo 374 | Getting image list signatures 375 | Copying 2 images generated from 2 images in list 376 | Copying image sha256:76535c50cab1708ff17dc67e93d2a06dea01978f7201d17fd6b28b32f8ce9555 (1/2) 377 | Getting image source signatures 378 | Copying blob 9e167103aefa skipped: already exists 379 | Copying blob bd9ddc54bea9 skipped: already exists 380 | Copying config 81b91103bc done | 381 | Writing manifest to image destination 382 | Copying image sha256:4eab20bcf7da10905cb95ce80141869e84854d15d99454e1365f10286d519f62 (2/2) 383 | Getting image source signatures 384 | Copying blob bd9ddc54bea9 skipped: already exists 385 | Copying blob 76f837f08b76 skipped: already exists 386 | Copying config 01d89888b7 done | 387 | Writing manifest to image destination 388 | Writing manifest list to image destination 389 | Storing list signatures 390 | [root@x86-instance multi-arch]# podman images --digests --no-trunc 391 | REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE 392 | localhost/demo latest sha256:20b959ad5960230b65a77b746bdbf5d991ade4d7a129c2554e167acdcc990531 sha256:0deab136998a9b9143d5b253b1b6e8a6d741cfeb5fd9641379a4317ec117bc38 6 minutes ago 833 B 393 | quay.io/openshift-examples/multi-arch demo-x86_64 sha256:66ade3f15bca773a0227d4ff479bb1191b5e5bb94da88bab7307284129bb1733 sha256:81b91103bcad946edabad074db3e3eefcbfccd307587b6b40257bb0932a31705 24 minutes ago 26.1 MB 394 | registry.access.redhat.com/ubi9/ubi-micro latest sha256:bd93cff066cc579e49d53f50782f7edad319031e9d511b1e8709cf16be8d78a0 sha256:1b9d4f56fb2cd4401fa14437e3f245e6872388ed3e50f72926234315cbf4f817 3 weeks ago 26.1 MB 395 | 396 | ``` 397 | 398 |
399 | Question: How to predict the Image ID (`6270f63fbb1c`) of the manifest? 400 | 401 | Red Hat internal slack #forum-container-engines: https://redhat-internal.slack.com/archives/CBBJY9GSX/p1696249069114529 402 | 403 | ``` 404 | [root@x86-instance storage]# podman manifest create localhost/demo2 405 | 6270f63fbb1c4ae4b18c82936f5be0c6523e77455a2565ee48013807b813a08c 406 | [root@x86-instance storage]# podman images --digests --no-trunc 407 | REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE 408 | localhost/demo2 latest sha256:20b959ad5960230b65a77b746bdbf5d991ade4d7a129c2554e167acdcc990531 sha256:6270f63fbb1c4ae4b18c82936f5be0c6523e77455a2565ee48013807b813a08c 20 seconds ago 110 B 409 | [root@x86-instance storage]# cat ./overlay-images/6270f63fbb1c4ae4b18c82936f5be0c6523e77455a2565ee48013807b813a08c/manifest 410 | {"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.list.v2+json","manifests":null}[root@x86-instance storage]# cat ./overlay-images/6270f63fbb1c4ae4b18c82936f5be0c6523e77455a2565ee48013807b813a08c/manifest | sha256sum 411 | 20b959ad5960230b65a77b746bdbf5d991ade4d7a129c2554e167acdcc990531 - 412 | [root@x86-instance storage]# pwd 413 | /var/lib/containers/storage 414 | [root@x86-instance storage]# cat overlay-images/images.json | jq 415 | .. 416 | { 417 | "id": "6270f63fbb1c4ae4b18c82936f5be0c6523e77455a2565ee48013807b813a08c", 418 | "digest": "sha256:20b959ad5960230b65a77b746bdbf5d991ade4d7a129c2554e167acdcc990531", 419 | "names": [ 420 | "localhost/demo2:latest" 421 | ], 422 | "big-data-names": [ 423 | "manifest", 424 | "instances.json" 425 | ], 426 | "big-data-sizes": { 427 | "instances.json": 2, 428 | "manifest": 108 429 | }, 430 | "big-data-digests": { 431 | "instances.json": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a", 432 | "manifest": "sha256:20b959ad5960230b65a77b746bdbf5d991ade4d7a129c2554e167acdcc990531" 433 | }, 434 | "created": "2023-10-01T20:03:26.300473396Z" 435 | } 436 | 437 | .. 438 | 439 | 440 | [root@x86-instance storage]# find | grep 6270 441 | ./overlay-images/6270f63fbb1c4ae4b18c82936f5be0c6523e77455a2565ee48013807b813a08c 442 | ./overlay-images/6270f63fbb1c4ae4b18c82936f5be0c6523e77455a2565ee48013807b813a08c/manifest 443 | ./overlay-images/6270f63fbb1c4ae4b18c82936f5be0c6523e77455a2565ee48013807b813a08c/instances.json 444 | 445 | 446 | ``` 447 | 448 |
449 | 450 | 451 | ## Discover via quay.io web ui 452 | 453 | 454 | 455 | ![assets/quay-multi-arch-overview.png](assets/quay-multi-arch-overview.png) 456 | 457 | ## Discover via explore.ggcr.dev 458 | 459 | 460 | 461 | 462 | ## Copy & Muli-Arch image and discover 463 | 464 | Deploy a registry, for example: 465 | 466 | 467 | 468 | Copy image into registry: 469 | 470 | ```bash 471 | export REGISTRY=registry-multi-arch-demo.apps.... 472 | 473 | skopeo copy --all \ 474 | docker://quay.io/openshift-examples/multi-arch:demo \ 475 | docker://${REGISTRY}/openshift-examples/multi-arch:demo 476 | 477 | # Optional - just the tags, blobs already copied. 478 | skopeo copy --all \ 479 | docker://quay.io/openshift-examples/multi-arch:demo-x86_64 \ 480 | docker://${REGISTRY}/openshift-examples/multi-arch:demo-x86_64 481 | skopeo copy --all \ 482 | docker://quay.io/openshift-examples/multi-arch:demo-aarch64 \ 483 | docker://${REGISTRY}/openshift-examples/multi-arch:demo-aarch64 484 | 485 | ``` 486 | 487 | Optional, set registry read-only: 488 | ```bash ="" 489 | oc patch deployment/registry -p '{"spec":{"template":{"spec":{"containers":[{"name":"registry","env":[{"name":"REGISTRY_STORAGE_MAINTENANCE_READONLY","value":"{\"enabled\":true}"}]}]}}}}' 490 | ``` 491 | 492 | ### Take a look into the registry 493 | 494 | [![alt text](https://img.youtube.com/vi/v_v1OhRcOZU/0.jpg)](https://www.youtube.com/watch?v=v_v1OhRcOZU) 495 | 496 | 497 | `oc rsh -c tools deployment/registry`: 498 | 499 | For example, double check the sha256 change 500 | 501 | ```bash 502 | sh-4.4# cd /registry/docker/registry/v2/blobs/sha256/76/76f837f08b7667f5c10d53f91ca4885797a2cfa13f195e9bd024ad9ad934d0d2/ 503 | sh-4.4# file * 504 | data: gzip compressed data, original size 27290112 505 | 506 | sh-4.4# cp data foo.gz 507 | sh-4.4# gzip -d foo.gz 508 | sh-4.4# sha256sum * 509 | 76f837f08b7667f5c10d53f91ca4885797a2cfa13f195e9bd024ad9ad934d0d2 data 510 | 791a6a33d694bf7f1a8a1373b17e2cead2c0e2ee17620cd64128acfa88d2a953 foo 511 | sh-4.4# 512 | ``` 513 | 514 | ## Multi-arch build 515 | 516 | ### via Podman Desktop or on Fedora Linux 517 | 518 | ```bash 519 | export IMAGE='quay.io/openshift-examples/multi-arch:podman-desktop-example' 520 | podman build --platform linux/amd64,linux/arm64 --manifest ${IMAGE} . 521 | podman manifest inspect ${IMAGE} 522 | podman manifest push ${IMAGE} 523 | skopeo inspect --raw docker://${IMAGE} | jq 524 | ``` 525 | 526 | ### via GitHub Actions 527 | 528 | Example: https://github.com/rbo/antora-viewer 529 | 530 | ```yaml 531 | jobs: 532 | cicd: 533 | runs-on: ubuntu-latest 534 | steps: 535 | - name: checkout 536 | uses: actions/checkout@v4 537 | - name: set datetime 538 | run: | 539 | echo "datetime=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV 540 | - name: Install qemu dependency 541 | run: | 542 | sudo apt-get update 543 | sudo apt-get install -y qemu-user-static 544 | - name: build image 545 | id: build-image 546 | uses: redhat-actions/buildah-build@v2 547 | with: 548 | image: ${{ github.repository }} 549 | tags: latest ${{ github.ref_name }} 550 | platforms: linux/amd64, linux/arm64 551 | context: ./container 552 | containerfiles: | 553 | ./container/Containerfile 554 | build-args: | 555 | CREATED_AT=${{ env.datetime }} 556 | GITHUB_SHA=${{ github.sha }} 557 | - name: push image to ghcr.io 558 | uses: redhat-actions/push-to-registry@v2 559 | with: 560 | image: ${{ steps.build-image.outputs.image }} 561 | tags: ${{ steps.build-image.outputs.tags }} 562 | registry: ghcr.io 563 | username: ${{ github.actor }} 564 | password: ${{ secrets.GITHUB_TOKEN }} 565 | ``` 566 | --------------------------------------------------------------------------------