Merge pull request #780 from bogdando/downloads
Add download_always_pull check and sha256 for docker images
This commit is contained in:
commit
cf4f2b4f14
5 changed files with 113 additions and 22 deletions
42
docs/downloads.md
Normal file
42
docs/downloads.md
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
Downloading binaries and containers
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Kargo supports several download/upload modes. The default is:
|
||||||
|
|
||||||
|
* Each node downloads binaries and container images on its own, which is
|
||||||
|
``download_run_once: False``.
|
||||||
|
* For K8s apps, pull policy is ``k8s_image_pull_policy: IfNotPresent``.
|
||||||
|
* For system managed containers, like kubelet or etcd, pull policy is
|
||||||
|
``download_always_pull: False``, which is pull if only the wanted repo and
|
||||||
|
tag/sha256 digest differs from that the host has.
|
||||||
|
|
||||||
|
There is also a "pull once, push many" mode as well:
|
||||||
|
|
||||||
|
* Override the ``download_run_once: True`` to download container images only once
|
||||||
|
then push to cluster nodes in batches. The default delegate node
|
||||||
|
for pushing images is the first `kube-master`.
|
||||||
|
* If your ansible runner node (aka the admin node) have password-less sudo and
|
||||||
|
docker enabled, you may want to define the ``download_localhost: True``, which
|
||||||
|
makes that node a delegate for pushing images while running the deployment with
|
||||||
|
ansible. This maybe the case if cluster nodes cannot access each over via ssh
|
||||||
|
or you want to use local docker images as a cache for multiple clusters.
|
||||||
|
|
||||||
|
Container images and binary files are described by the vars like ``foo_version``,
|
||||||
|
``foo_download_url``, ``foo_checksum`` for binaries and ``foo_image_repo``,
|
||||||
|
``foo_image_tag`` or optional ``foo_digest_checksum`` for containers.
|
||||||
|
|
||||||
|
Container images may be defined by its repo and tag, for example:
|
||||||
|
`andyshinn/dnsmasq:2.72`. Or by repo and tag and sha256 digest:
|
||||||
|
`andyshinn/dnsmasq@sha256:7c883354f6ea9876d176fe1d30132515478b2859d6fc0cbf9223ffdc09168193`.
|
||||||
|
|
||||||
|
Note, the sha256 digest and the image tag must be both specified and correspond
|
||||||
|
to each other. The given example above is represented by the following vars:
|
||||||
|
```
|
||||||
|
dnsmasq_digest_checksum: 7c883354f6ea9876d176fe1d30132515478b2859d6fc0cbf9223ffdc09168193
|
||||||
|
dnsmasq_image_repo: andyshinn/dnsmasq
|
||||||
|
dnsmasq_image_tag: '2.72'
|
||||||
|
```
|
||||||
|
The full list of available vars may be found in the download's ansible role defaults.
|
||||||
|
Those also allow to specify custom urls and local repositories for binaries and container
|
||||||
|
images as well. See also the DNS stack docs for the related intranet configuration,
|
||||||
|
so the hosts can resolve those urls and repos.
|
|
@ -8,14 +8,8 @@ For a large scaled deployments, consider the following configuration changes:
|
||||||
|
|
||||||
* Override containers' `foo_image_repo` vars to point to intranet registry.
|
* Override containers' `foo_image_repo` vars to point to intranet registry.
|
||||||
|
|
||||||
* Override the ``download_run_once: true`` to download container images only once
|
* Override the ``download_run_once: true`` and/or ``download_localhost: true``.
|
||||||
then push to cluster nodes in batches. The default delegate node
|
See download modes for details.
|
||||||
for pushing images is the first kube-master. Note, if you have passwordless sudo
|
|
||||||
and docker enabled on the separate admin node, you may want to define the
|
|
||||||
``download_localhost: true``, which makes that node a delegate for pushing images
|
|
||||||
while running the deployment with ansible. This maybe the case if cluster nodes
|
|
||||||
cannot access each over via ssh or you want to use local docker images as a cache
|
|
||||||
for multiple clusters.
|
|
||||||
|
|
||||||
* Adjust the `retry_stagger` global var as appropriate. It should provide sane
|
* Adjust the `retry_stagger` global var as appropriate. It should provide sane
|
||||||
load on a delegate (the first K8s master node) then retrying failed
|
load on a delegate (the first K8s master node) then retrying failed
|
||||||
|
|
|
@ -14,6 +14,9 @@ download_compress: 9
|
||||||
# in the download_run_once mode.
|
# in the download_run_once mode.
|
||||||
download_localhost: False
|
download_localhost: False
|
||||||
|
|
||||||
|
# Always pull images if set to True. Otherwise check by the repo's tag/digest.
|
||||||
|
download_always_pull: False
|
||||||
|
|
||||||
# Versions
|
# Versions
|
||||||
etcd_version: v3.0.6
|
etcd_version: v3.0.6
|
||||||
#TODO(mattymo): Move calico versions to roles/network_plugins/calico/defaults
|
#TODO(mattymo): Move calico versions to roles/network_plugins/calico/defaults
|
||||||
|
@ -85,16 +88,19 @@ downloads:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ netcheck_server_img_repo }}"
|
repo: "{{ netcheck_server_img_repo }}"
|
||||||
tag: "{{ netcheck_tag }}"
|
tag: "{{ netcheck_tag }}"
|
||||||
|
sha256: "{{ netcheck_server_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ deploy_netchecker|bool }}"
|
enabled: "{{ deploy_netchecker|bool }}"
|
||||||
netcheck_agent:
|
netcheck_agent:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ netcheck_agent_img_repo }}"
|
repo: "{{ netcheck_agent_img_repo }}"
|
||||||
tag: "{{ netcheck_tag }}"
|
tag: "{{ netcheck_tag }}"
|
||||||
|
sha256: "{{ netcheck_agent_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ deploy_netchecker|bool }}"
|
enabled: "{{ deploy_netchecker|bool }}"
|
||||||
netcheck_kubectl:
|
netcheck_kubectl:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ netcheck_kubectl_img_repo }}"
|
repo: "{{ netcheck_kubectl_img_repo }}"
|
||||||
tag: "{{ netcheck_kubectl_tag }}"
|
tag: "{{ netcheck_kubectl_tag }}"
|
||||||
|
sha256: "{{ netcheck_kubectl_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ deploy_netchecker|bool }}"
|
enabled: "{{ deploy_netchecker|bool }}"
|
||||||
weave:
|
weave:
|
||||||
dest: weave/bin/weave
|
dest: weave/bin/weave
|
||||||
|
@ -108,7 +114,8 @@ downloads:
|
||||||
etcd:
|
etcd:
|
||||||
version: "{{etcd_version}}"
|
version: "{{etcd_version}}"
|
||||||
dest: "etcd/etcd-{{ etcd_version }}-linux-amd64.tar.gz"
|
dest: "etcd/etcd-{{ etcd_version }}-linux-amd64.tar.gz"
|
||||||
sha256: "{{ etcd_checksum }}"
|
sha256: >-
|
||||||
|
{%- if etcd_deployment_type == 'docker' -%}{{etcd_digest_checksum|default(None)}}{%- else -%}{{etcd_checksum}}{%- endif -%}
|
||||||
source_url: "{{ etcd_download_url }}"
|
source_url: "{{ etcd_download_url }}"
|
||||||
url: "{{ etcd_download_url }}"
|
url: "{{ etcd_download_url }}"
|
||||||
unarchive: true
|
unarchive: true
|
||||||
|
@ -121,64 +128,78 @@ downloads:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ hyperkube_image_repo }}"
|
repo: "{{ hyperkube_image_repo }}"
|
||||||
tag: "{{ hyperkube_image_tag }}"
|
tag: "{{ hyperkube_image_tag }}"
|
||||||
|
sha256: "{{ hyperkube_digest_checksum|default(None) }}"
|
||||||
flannel:
|
flannel:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ flannel_image_repo }}"
|
repo: "{{ flannel_image_repo }}"
|
||||||
tag: "{{ flannel_image_tag }}"
|
tag: "{{ flannel_image_tag }}"
|
||||||
|
sha256: "{{ flannel_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ kube_network_plugin == 'flannel' or kube_network_plugin == 'canal' }}"
|
enabled: "{{ kube_network_plugin == 'flannel' or kube_network_plugin == 'canal' }}"
|
||||||
calicoctl:
|
calicoctl:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ calicoctl_image_repo }}"
|
repo: "{{ calicoctl_image_repo }}"
|
||||||
tag: "{{ calicoctl_image_tag }}"
|
tag: "{{ calicoctl_image_tag }}"
|
||||||
|
sha256: "{{ calicoctl_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
|
enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
|
||||||
calico_node:
|
calico_node:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ calico_node_image_repo }}"
|
repo: "{{ calico_node_image_repo }}"
|
||||||
tag: "{{ calico_node_image_tag }}"
|
tag: "{{ calico_node_image_tag }}"
|
||||||
|
sha256: "{{ calico_node_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
|
enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
|
||||||
calico_cni:
|
calico_cni:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ calico_cni_image_repo }}"
|
repo: "{{ calico_cni_image_repo }}"
|
||||||
tag: "{{ calico_cni_image_tag }}"
|
tag: "{{ calico_cni_image_tag }}"
|
||||||
|
sha256: "{{ calico_cni_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
|
enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
|
||||||
calico_policy:
|
calico_policy:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ calico_policy_image_repo }}"
|
repo: "{{ calico_policy_image_repo }}"
|
||||||
tag: "{{ calico_policy_image_tag }}"
|
tag: "{{ calico_policy_image_tag }}"
|
||||||
|
sha256: "{{ calico_policy_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ kube_network_plugin == 'canal' }}"
|
enabled: "{{ kube_network_plugin == 'canal' }}"
|
||||||
calico_rr:
|
calico_rr:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ calico_rr_image_repo }}"
|
repo: "{{ calico_rr_image_repo }}"
|
||||||
tag: "{{ calico_rr_image_tag }}"
|
tag: "{{ calico_rr_image_tag }}"
|
||||||
|
sha256: "{{ calico_rr_digest_checksum|default(None) }}"
|
||||||
enabled: "{{ peer_with_calico_rr is defined and peer_with_calico_rr}} and kube_network_plugin == 'calico'"
|
enabled: "{{ peer_with_calico_rr is defined and peer_with_calico_rr}} and kube_network_plugin == 'calico'"
|
||||||
pod_infra:
|
pod_infra:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ pod_infra_image_repo }}"
|
repo: "{{ pod_infra_image_repo }}"
|
||||||
tag: "{{ pod_infra_image_tag }}"
|
tag: "{{ pod_infra_image_tag }}"
|
||||||
|
sha256: "{{ pod_infra_digest_checksum|default(None) }}"
|
||||||
nginx:
|
nginx:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ nginx_image_repo }}"
|
repo: "{{ nginx_image_repo }}"
|
||||||
tag: "{{ nginx_image_tag }}"
|
tag: "{{ nginx_image_tag }}"
|
||||||
|
sha256: "{{ nginx_digest_checksum|default(None) }}"
|
||||||
dnsmasq:
|
dnsmasq:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ dnsmasq_image_repo }}"
|
repo: "{{ dnsmasq_image_repo }}"
|
||||||
tag: "{{ dnsmasq_image_tag }}"
|
tag: "{{ dnsmasq_image_tag }}"
|
||||||
|
sha256: "{{ dnsmasq_digest_checksum|default(None) }}"
|
||||||
kubednsmasq:
|
kubednsmasq:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ kubednsmasq_image_repo }}"
|
repo: "{{ kubednsmasq_image_repo }}"
|
||||||
tag: "{{ kubednsmasq_image_tag }}"
|
tag: "{{ kubednsmasq_image_tag }}"
|
||||||
|
sha256: "{{ kubednsmasq_digest_checksum|default(None) }}"
|
||||||
kubedns:
|
kubedns:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ kubedns_image_repo }}"
|
repo: "{{ kubedns_image_repo }}"
|
||||||
tag: "{{ kubedns_image_tag }}"
|
tag: "{{ kubedns_image_tag }}"
|
||||||
|
sha256: "{{ kubedns_digest_checksum|default(None) }}"
|
||||||
testbox:
|
testbox:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ test_image_repo }}"
|
repo: "{{ test_image_repo }}"
|
||||||
tag: "{{ test_image_tag }}"
|
tag: "{{ test_image_tag }}"
|
||||||
|
sha256: "{{ testbox_digest_checksum|default(None) }}"
|
||||||
exechealthz:
|
exechealthz:
|
||||||
container: true
|
container: true
|
||||||
repo: "{{ exechealthz_image_repo }}"
|
repo: "{{ exechealthz_image_repo }}"
|
||||||
tag: "{{ exechealthz_image_tag }}"
|
tag: "{{ exechealthz_image_tag }}"
|
||||||
|
sha256: "{{ exechealthz_digest_checksum|default(None) }}"
|
||||||
|
|
||||||
download:
|
download:
|
||||||
container: "{{ file.container|default('false') }}"
|
container: "{{ file.container|default('false') }}"
|
||||||
|
|
|
@ -39,11 +39,6 @@
|
||||||
mode: "{{ download.mode|default(omit) }}"
|
mode: "{{ download.mode|default(omit) }}"
|
||||||
when: "{{ download.enabled|bool and not download.container|bool and (download.unarchive is not defined or download.unarchive == False) }}"
|
when: "{{ download.enabled|bool and not download.container|bool and (download.unarchive is not defined or download.unarchive == False) }}"
|
||||||
|
|
||||||
- name: pulling...
|
|
||||||
debug:
|
|
||||||
msg: "{{ download.repo }}:{{ download.tag }}"
|
|
||||||
when: "{{ download.enabled|bool and download.container|bool }}"
|
|
||||||
|
|
||||||
- set_fact:
|
- set_fact:
|
||||||
download_delegate: "{% if download_localhost %}localhost{% else %}{{groups['kube-master'][0]}}{% endif %}"
|
download_delegate: "{% if download_localhost %}localhost{% else %}{{groups['kube-master'][0]}}{% endif %}"
|
||||||
tags: facts
|
tags: facts
|
||||||
|
@ -70,29 +65,41 @@
|
||||||
when: "{{ download_run_once|bool and download.enabled|bool and download.container|bool and download_delegate == 'localhost' }}"
|
when: "{{ download_run_once|bool and download.enabled|bool and download.container|bool and download_delegate == 'localhost' }}"
|
||||||
tags: localhost
|
tags: localhost
|
||||||
|
|
||||||
|
- name: Make download decision if pull is required by tag or sha256
|
||||||
|
include: set_docker_image_facts.yml
|
||||||
|
when: "{{ download.enabled|bool and download.container|bool }}"
|
||||||
|
delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
|
||||||
|
run_once: "{{ download_run_once|bool }}"
|
||||||
|
tags: facts
|
||||||
|
|
||||||
|
- name: pulling...
|
||||||
|
debug:
|
||||||
|
msg: "{{ pull_args }}"
|
||||||
|
when: "{{ download.enabled|bool and download.container|bool }}"
|
||||||
|
|
||||||
#NOTE(bogdando) this brings no docker-py deps for nodes
|
#NOTE(bogdando) this brings no docker-py deps for nodes
|
||||||
- name: Download containers
|
- name: Download containers if pull is required or told to always pull
|
||||||
command: "/usr/bin/docker pull {{ download.repo }}:{{ download.tag }}"
|
command: "/usr/bin/docker pull {{ pull_args }}"
|
||||||
register: pull_task_result
|
register: pull_task_result
|
||||||
until: pull_task_result|success
|
until: pull_task_result|success
|
||||||
retries: 4
|
retries: 4
|
||||||
delay: "{{ retry_stagger | random + 3 }}"
|
delay: "{{ retry_stagger | random + 3 }}"
|
||||||
when: "{{ download.enabled|bool and download.container|bool }}"
|
when: "{{ download.enabled|bool and download.container|bool and pull_required|bool|default(download_always_pull) }}"
|
||||||
delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
|
delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
|
||||||
run_once: "{{ download_run_once|bool }}"
|
run_once: "{{ download_run_once|bool }}"
|
||||||
|
|
||||||
- set_fact:
|
- set_fact:
|
||||||
fname: "{{local_release_dir}}/containers/{{download.repo|regex_replace('/|\0|:', '_')}}:{{download.tag|regex_replace('/|\0|:', '_')}}.tar"
|
fname: "{{local_release_dir}}/containers/{{download.repo|regex_replace('/|\0|:', '_')}}:{{download.tag|default(download.sha256)|regex_replace('/|\0|:', '_')}}.tar"
|
||||||
tags: facts
|
tags: facts
|
||||||
|
|
||||||
- name: "Set default value for 'container_changed' to false"
|
- name: "Set default value for 'container_changed' to false"
|
||||||
set_fact:
|
set_fact:
|
||||||
container_changed: false
|
container_changed: "{{pull_required|bool|default(false)}}"
|
||||||
|
|
||||||
- name: "Update the 'container_changed' fact"
|
- name: "Update the 'container_changed' fact"
|
||||||
set_fact:
|
set_fact:
|
||||||
container_changed: "{{ not 'up to date' in pull_task_result.stdout }}"
|
container_changed: "{{ pull_required|bool|default(false) or not 'up to date' in pull_task_result.stdout }}"
|
||||||
when: "{{ download.enabled|bool and download.container|bool }}"
|
when: "{{ download.enabled|bool and download.container|bool and pull_required|bool|default(download_always_pull) }}"
|
||||||
delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
|
delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
|
||||||
run_once: "{{ download_run_once|bool }}"
|
run_once: "{{ download_run_once|bool }}"
|
||||||
tags: facts
|
tags: facts
|
||||||
|
@ -108,7 +115,7 @@
|
||||||
tags: facts
|
tags: facts
|
||||||
|
|
||||||
- name: Download | save container images
|
- name: Download | save container images
|
||||||
shell: docker save "{{ download.repo }}:{{ download.tag }}" | gzip -{{ download_compress }} > "{{ fname }}"
|
shell: docker save "{{ pull_args }}" | gzip -{{ download_compress }} > "{{ fname }}"
|
||||||
delegate_to: "{{ download_delegate }}"
|
delegate_to: "{{ download_delegate }}"
|
||||||
register: saved
|
register: saved
|
||||||
run_once: true
|
run_once: true
|
||||||
|
|
27
roles/download/tasks/set_docker_image_facts.yml
Normal file
27
roles/download/tasks/set_docker_image_facts.yml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
- set_fact:
|
||||||
|
pull_by_digest: >-
|
||||||
|
{%- if download.sha256 is defined and download.sha256 != '' -%}true{%- else -%}false{%- endif -%}
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
pull_args: >-
|
||||||
|
{%- if pull_by_digest|bool %}{{download.repo}}@sha256:{{download.sha256}}{%- else -%}{{download.repo}}:{{download.tag}}{%- endif -%}
|
||||||
|
|
||||||
|
- name: Register docker images info
|
||||||
|
shell: "{% raw %}/usr/bin/docker images -q | xargs /usr/bin/docker inspect -f '{{.RepoTags}},{{.RepoDigests}}'{% endraw %}"
|
||||||
|
register: docker_images_raw
|
||||||
|
ignore_errors: true
|
||||||
|
when: not download_always_pull|bool
|
||||||
|
|
||||||
|
- set_fact: docker_images="{{docker_images_raw.stdout|regex_replace('\[|\]|\\n]','')|regex_replace('\s',',')}}"
|
||||||
|
when: not download_always_pull|bool
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
pull_required: >-
|
||||||
|
{%- if pull_args in docker_images.split(',') %}false{%- else -%}true{%- endif -%}
|
||||||
|
when: not download_always_pull|bool
|
||||||
|
|
||||||
|
- name: Check the local digest sha256 corresponds to the given image tag
|
||||||
|
assert:
|
||||||
|
that: "{{download.repo}}:{{download.tag}} in docker_images.split(',')"
|
||||||
|
when: not download_always_pull|bool and not pull_required|bool and pull_by_digest|bool
|
Loading…
Reference in a new issue