diff --git a/docs/ansible.md b/docs/ansible.md index 7aca19e01..1388186e3 100644 --- a/docs/ansible.md +++ b/docs/ansible.md @@ -202,6 +202,7 @@ The following tags are defined in playbooks: | vsphere-csi-driver | Configuring csi driver: vsphere | weave | Network plugin Weave | win_nodes | Running windows specific tasks +| youki | Configuring youki runtime Note: Use the ``bash scripts/gen_tags.sh`` command to generate a list of all tags found in the codebase. New tags will be listed with the empty "Used for" diff --git a/roles/container-engine/cri-o/defaults/main.yml b/roles/container-engine/cri-o/defaults/main.yml index 912428ff0..422bddfaf 100644 --- a/roles/container-engine/cri-o/defaults/main.yml +++ b/roles/container-engine/cri-o/defaults/main.yml @@ -73,6 +73,13 @@ crun_runtime: type: oci root: /run/crun +# youki is an implementation of the OCI runtime-spec in Rust, similar to runc. +youki_runtime: + name: youki + path: "{{ youki_bin_dir }}/youki" + type: oci + root: /run/youki + # When this is true, CRI-O package repositories are added. Set this to false when using an # environment with preconfigured CRI-O package repositories. crio_add_repos: true diff --git a/roles/container-engine/cri-o/tasks/main.yaml b/roles/container-engine/cri-o/tasks/main.yaml index 46ef43548..3fb6ea0f6 100644 --- a/roles/container-engine/cri-o/tasks/main.yaml +++ b/roles/container-engine/cri-o/tasks/main.yaml @@ -54,6 +54,12 @@ when: - crun_enabled +- name: Build a list of crio runtimes with youki runtime + set_fact: + crio_runtimes: "{{ crio_runtimes + [youki_runtime] }}" + when: + - youki_enabled + - name: Make sure needed folders exist in the system with_items: - /etc/crio diff --git a/roles/container-engine/meta/main.yml b/roles/container-engine/meta/main.yml index 8bd98bd02..7ef823629 100644 --- a/roles/container-engine/meta/main.yml +++ b/roles/container-engine/meta/main.yml @@ -23,6 +23,14 @@ dependencies: - container-engine - crun + - role: container-engine/youki + when: + - youki_enabled + - container_manager == 'crio' + tags: + - container-engine + - youki + - role: container-engine/cri-o when: - container_manager == 'crio' diff --git a/roles/container-engine/youki/defaults/main.yml b/roles/container-engine/youki/defaults/main.yml new file mode 100644 index 000000000..2250f22ae --- /dev/null +++ b/roles/container-engine/youki/defaults/main.yml @@ -0,0 +1,3 @@ +--- + +youki_bin_dir: "{{ bin_dir }}" diff --git a/roles/container-engine/youki/molecule/default/converge.yml b/roles/container-engine/youki/molecule/default/converge.yml new file mode 100644 index 000000000..11ef8f6bf --- /dev/null +++ b/roles/container-engine/youki/molecule/default/converge.yml @@ -0,0 +1,11 @@ +--- +- name: Converge + hosts: all + become: true + vars: + youki_enabled: true + container_manager: crio + roles: + - role: kubespray-defaults + - role: container-engine/cri-o + - role: container-engine/youki diff --git a/roles/container-engine/youki/molecule/default/files/10-mynet.conf b/roles/container-engine/youki/molecule/default/files/10-mynet.conf new file mode 100644 index 000000000..b9fa3ba73 --- /dev/null +++ b/roles/container-engine/youki/molecule/default/files/10-mynet.conf @@ -0,0 +1,17 @@ +{ + "cniVersion": "0.4.0", + "name": "mynet", + "type": "bridge", + "bridge": "cni0", + "isGateway": true, + "ipMasq": true, + "ipam": { + "type": "host-local", + "subnet": "172.19.0.0/24", + "routes": [ + { + "dst": "0.0.0.0/0" + } + ] + } +} diff --git a/roles/container-engine/youki/molecule/default/files/container.json b/roles/container-engine/youki/molecule/default/files/container.json new file mode 100644 index 000000000..a5d509431 --- /dev/null +++ b/roles/container-engine/youki/molecule/default/files/container.json @@ -0,0 +1,10 @@ +{ + "metadata": { + "name": "youki1" + }, + "image": { + "image": "quay.io/kubespray/hello-world:latest" + }, + "log_path": "youki1.0.log", + "linux": {} +} diff --git a/roles/container-engine/youki/molecule/default/files/sandbox.json b/roles/container-engine/youki/molecule/default/files/sandbox.json new file mode 100644 index 000000000..b2a4ffe50 --- /dev/null +++ b/roles/container-engine/youki/molecule/default/files/sandbox.json @@ -0,0 +1,10 @@ +{ + "metadata": { + "name": "youki1", + "namespace": "default", + "attempt": 1, + "uid": "hdishd83djaidwnduwk28bcsb" + }, + "linux": {}, + "log_directory": "/tmp" +} diff --git a/roles/container-engine/youki/molecule/default/molecule.yml b/roles/container-engine/youki/molecule/default/molecule.yml new file mode 100644 index 000000000..14867fad5 --- /dev/null +++ b/roles/container-engine/youki/molecule/default/molecule.yml @@ -0,0 +1,45 @@ +--- +driver: + name: vagrant + provider: + name: libvirt + options: + driver: kvm +lint: | + set -e + yamllint -c ../../../.yamllint . +platforms: + - name: ubuntu20 + box: generic/ubuntu2004 + cpus: 1 + memory: 1024 + nested: true + groups: + - kube_control_plane + - name: almalinux8 + box: almalinux/8 + cpus: 1 + memory: 1024 + nested: true + groups: + - kube_control_plane +provisioner: + name: ansible + env: + ANSIBLE_ROLES_PATH: ../../../../ + config_options: + defaults: + callback_whitelist: profile_tasks + timeout: 120 + lint: + name: ansible-lint + options: + c: ../../../.ansible-lint + inventory: + group_vars: + all: + become: true +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/container-engine/youki/molecule/default/prepare.yml b/roles/container-engine/youki/molecule/default/prepare.yml new file mode 100644 index 000000000..e9486865f --- /dev/null +++ b/roles/container-engine/youki/molecule/default/prepare.yml @@ -0,0 +1,48 @@ +--- +- name: Prepare generic + hosts: all + become: true + roles: + - role: kubespray-defaults + - role: bootstrap-os + - role: adduser + user: "{{ addusers.kube }}" + tasks: + - include_tasks: "../../../../download/tasks/download_file.yml" + vars: + download: "{{ download_defaults | combine(downloads.cni) }}" + +- name: Prepare container runtime + hosts: all + become: true + vars: + container_manager: crio + kube_network_plugin: cni + roles: + - role: kubespray-defaults + - role: network_plugin/cni + - role: container-engine/crictl + tasks: + - name: Copy test container files + copy: + src: "{{ item }}" + dest: "/tmp/{{ item }}" + owner: root + mode: 0644 + with_items: + - container.json + - sandbox.json + - name: Create /etc/cni/net.d directory + file: + path: /etc/cni/net.d + state: directory + owner: root + mode: 0755 + - name: Setup CNI + copy: + src: "{{ item }}" + dest: "/etc/cni/net.d/{{ item }}" + owner: root + mode: 0644 + with_items: + - 10-mynet.conf diff --git a/roles/container-engine/youki/molecule/default/tests/test_default.py b/roles/container-engine/youki/molecule/default/tests/test_default.py new file mode 100644 index 000000000..54ed5c54c --- /dev/null +++ b/roles/container-engine/youki/molecule/default/tests/test_default.py @@ -0,0 +1,29 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_run(host): + youkiruntime = "/usr/local/bin/youki" + with host.sudo(): + cmd = host.command(youkiruntime + " --version") + assert cmd.rc == 0 + assert "youki" in cmd.stdout + + +def test_run_pod(host): + runtime = "youki" + + run_command = "/usr/local/bin/crictl run --with-pull --runtime {} /tmp/container.json /tmp/sandbox.json".format(runtime) + with host.sudo(): + cmd = host.command(run_command) + assert cmd.rc == 0 + + with host.sudo(): + log_f = host.file("/tmp/youki1.0.log") + + assert log_f.exists + assert b"Hello from Docker" in log_f.content diff --git a/roles/container-engine/youki/tasks/main.yml b/roles/container-engine/youki/tasks/main.yml new file mode 100644 index 000000000..1095c3d2e --- /dev/null +++ b/roles/container-engine/youki/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: youki | Download youki + include_tasks: "../../../download/tasks/download_file.yml" + vars: + download: "{{ download_defaults | combine(downloads.youki) }}" + +- name: youki | Copy youki binary from download dir + copy: + src: "{{ local_release_dir }}/youki_v{{ youki_version | regex_replace('\\.', '_') }}_linux/youki-v{{ youki_version }}/youki" + dest: "{{ youki_bin_dir }}/youki" + mode: 0755 + remote_src: true diff --git a/roles/download/defaults/main.yml b/roles/download/defaults/main.yml index 5087055e8..3f699c8fc 100644 --- a/roles/download/defaults/main.yml +++ b/roles/download/defaults/main.yml @@ -72,6 +72,7 @@ kubeadm_version: "{{ kube_version }}" crun_version: 1.4 runc_version: v1.0.3 kata_containers_version: 2.2.3 +youki_version: 0.0.1 gvisor_version: 20210921 containerd_version: 1.5.9 @@ -142,6 +143,7 @@ crictl_download_url: "https://github.com/kubernetes-sigs/cri-tools/releases/down helm_download_url: "https://get.helm.sh/helm-{{ helm_version }}-linux-{{ image_arch }}.tar.gz" runc_download_url: "https://github.com/opencontainers/runc/releases/download/{{ runc_version }}/runc.{{ image_arch }}" crun_download_url: "https://github.com/containers/crun/releases/download/{{ crun_version }}/crun-{{ crun_version }}-linux-{{ image_arch }}" +youki_download_url: "https://github.com/containers/youki/releases/download/v{{ youki_version }}/youki_v{{ youki_version | regex_replace('\\.', '_') }}_linux.tar.gz" kata_containers_download_url: "https://github.com/kata-containers/kata-containers/releases/download/{{ kata_containers_version }}/kata-static-{{ kata_containers_version }}-{{ ansible_architecture }}.tar.xz" # gVisor only supports amd64 and uses x86_64 to in the download link gvisor_runsc_download_url: "https://storage.googleapis.com/gvisor/releases/release/{{ gvisor_version }}/{{ ansible_architecture }}/runsc" @@ -430,6 +432,14 @@ crun_checksums: 1.3: c0955cf6d3d832c0249bbaa71ed235abb35b8ca45fe07f2bd4501a00afb9bdc4 1.4: 8e8081562503308f39f571acfe94afc663816ea0cb8f922145e2aaf0991415d7 +youki_checksums: + arm: + 0.0.1: 0 + amd64: + 0.0.1: 8bd712fe95c8a81194bfbc54c70516350f95153d67044579af95788fbafd943b + arm64: + 0.0.1: 0 + kata_containers_binary_checksums: arm: 2.0.4: 0 @@ -512,6 +522,7 @@ crictl_binary_checksum: "{{ crictl_checksums[image_arch][crictl_version] }}" helm_archive_checksum: "{{ helm_archive_checksums[image_arch][helm_version] }}" runc_binary_checksum: "{{ runc_checksums[image_arch][runc_version] }}" crun_binary_checksum: "{{ crun_checksums[image_arch][crun_version] }}" +youki_archive_checksum: "{{ youki_checksums[image_arch][youki_version] }}" kata_containers_binary_checksum: "{{ kata_containers_binary_checksums[image_arch][kata_containers_version] }}" gvisor_runsc_binary_checksum: "{{ gvisor_runsc_binary_checksums[image_arch][gvisor_version] }}" gvisor_containerd_shim_binary_checksum: "{{ gvisor_containerd_shim_binary_checksums[image_arch][gvisor_version] }}" @@ -809,6 +820,19 @@ downloads: groups: - k8s_cluster + youki: + file: true + enabled: "{{ youki_enabled }}" + version: "{{ youki_version }}" + dest: "{{ local_release_dir }}/youki_v{{ youki_version | regex_replace('\\.', '_') }}_linux.tar.gz" + sha256: "{{ youki_archive_checksum }}" + url: "{{ youki_download_url }}" + unarchive: true + owner: "root" + mode: "0755" + groups: + - k8s_cluster + runc: file: true enabled: "{{ container_manager == 'containerd' }}" diff --git a/roles/kubernetes-apps/container_runtimes/meta/main.yml b/roles/kubernetes-apps/container_runtimes/meta/main.yml index f63d38d61..8584117ef 100644 --- a/roles/kubernetes-apps/container_runtimes/meta/main.yml +++ b/roles/kubernetes-apps/container_runtimes/meta/main.yml @@ -20,3 +20,12 @@ dependencies: - apps - crun - container-runtimes + + - role: kubernetes-apps/container_runtimes/youki + when: + - youki_enabled + - container_manager == 'crio' + tags: + - apps + - youki + - container-runtimes diff --git a/roles/kubernetes-apps/container_runtimes/youki/tasks/main.yaml b/roles/kubernetes-apps/container_runtimes/youki/tasks/main.yaml new file mode 100644 index 000000000..6da025f04 --- /dev/null +++ b/roles/kubernetes-apps/container_runtimes/youki/tasks/main.yaml @@ -0,0 +1,19 @@ +--- + +- name: youki | Copy runtime class manifest + template: + src: runtimeclass-youki.yml + dest: "{{ kube_config_dir }}/runtimeclass-youki.yml" + mode: "0664" + when: + - inventory_hostname == groups['kube_control_plane'][0] + +- name: youki | Apply manifests + kube: + name: "runtimeclass-youki" + kubectl: "{{ bin_dir }}/kubectl" + resource: "runtimeclass" + filename: "{{ kube_config_dir }}/runtimeclass-youki.yml" + state: "latest" + when: + - inventory_hostname == groups['kube_control_plane'][0] diff --git a/roles/kubernetes-apps/container_runtimes/youki/templates/runtimeclass-youki.yml b/roles/kubernetes-apps/container_runtimes/youki/templates/runtimeclass-youki.yml new file mode 100644 index 000000000..b68bd0699 --- /dev/null +++ b/roles/kubernetes-apps/container_runtimes/youki/templates/runtimeclass-youki.yml @@ -0,0 +1,6 @@ +--- +kind: RuntimeClass +apiVersion: node.k8s.io/v1 +metadata: + name: youki +handler: youki diff --git a/roles/kubespray-defaults/defaults/main.yaml b/roles/kubespray-defaults/defaults/main.yaml index c9f6b8011..ada5bfa7d 100644 --- a/roles/kubespray-defaults/defaults/main.yaml +++ b/roles/kubespray-defaults/defaults/main.yaml @@ -275,6 +275,10 @@ gvisor_enabled: false # When enabled, it requires container_manager=crio crun_enabled: false +# Enable youki as additional container runtime +# When enabled, it requires container_manager=crio +youki_enabled: false + # Container on localhost (download images when download_localhost is true) container_manager_on_localhost: "{{ container_manager }}"