diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 52eb5c290f..e76431d565 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -14,6 +14,9 @@ aliases: - mboersma image-builder-openstack-reviewers: - hidekazuna + image-builder-openstack-maintainers + - drew-viles + - yankcrime image-builder-cloudstack-reviewers: - rohityadavcloud - davidjumani diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md index 5f10d94c39..d98661a195 100644 --- a/docs/book/src/SUMMARY.md +++ b/docs/book/src/SUMMARY.md @@ -11,6 +11,7 @@ - [GCP](./capi/providers/gcp.md) - [Nutanix](./capi/providers/nutanix.md) - [OpenStack](./capi/providers/openstack.md) + - [OpenStack remote image building](./capi/providers/openstack-remote.md) - [OCI](./capi/providers/oci.md) - [raw](./capi/providers/raw.md) - [vSphere](./capi/providers/vsphere.md) diff --git a/docs/book/src/capi/capi.md b/docs/book/src/capi/capi.md index 58fec2f514..7f1a7996b5 100644 --- a/docs/book/src/capi/capi.md +++ b/docs/book/src/capi/capi.md @@ -23,6 +23,7 @@ If any needed binaries are not present, they can be installed to `images/capi/.b * [OCI](./providers/oci.md) * [3DSOutscale](./providers/3dsoutscale.md) * [OpenStack](./providers/openstack.md) +* [OpenStack remote image building](./providers/openstack-remote.md) * [Raw](./providers/raw.md) * [VirtualBox](./providers/virtualbox.md) * [vSphere](./providers/vsphere.md) diff --git a/docs/book/src/capi/providers/oci.md b/docs/book/src/capi/providers/oci.md index 66b6dd9458..c37b289168 100644 --- a/docs/book/src/capi/providers/oci.md +++ b/docs/book/src/capi/providers/oci.md @@ -129,4 +129,4 @@ The following example JSON would use the [Windows Server 2019 Datacenter Edition "subnet_ocid": "Fill Subnet OCID here", "availability_domain": "Fill Availability Domain here" } -``` \ No newline at end of file +``` diff --git a/docs/book/src/capi/providers/openstack-remote.md b/docs/book/src/capi/providers/openstack-remote.md new file mode 100644 index 0000000000..3d83335811 --- /dev/null +++ b/docs/book/src/capi/providers/openstack-remote.md @@ -0,0 +1,75 @@ +# Building Images on OpenStack + +## Hypervisor + +The image is built using OpenStack. + +### Prerequisites for OpenStack builds + +First, check for prerequisites at [Packer docs for the OpenStack builder](https://developer.hashicorp.com/packer/plugins/builders/openstack). + +Also ensure that you have a [Ubuntu 20.04](https://cloud-images.ubuntu.com/focal/current/) or [Ubuntu 22.04](https://cloud-images.ubuntu.com/jammy/current/) cloud image available in your OpenStack instance before continuing as it will need to be referenced. +This build process also supports Flatcar Linux, but only Stable has been tested. + +#### Note +> Other operating systems could be supported and additions are welcome. + +## Setup Openstack authentication +Ensure you have set up your method of authentication. See the [examples here](https://docs.openstack.org/python-openstackclient/zed/cli/authentication.html). +You can also check out the [packer builder](https://developer.hashicorp.com/packer/plugins/builders/openstack#configuration-reference) for more information on authentication. + +You should be able to run commands against OpenStack before running this builder, otherwise it will fail. +You can test with a simple command such as `openstack image list`. + +## Building Images + +The build [prerequisites](../capi.md#prerequisites) for using `image-builder` for +building OpenStack images are managed by running: + +```bash +cd image-builder/images/capi +make deps-openstack +``` + +### Define variables for OpenStack build + +Using the [Openstack packer provider](https://developer.hashicorp.com/packer/plugins/builders/openstack), an instance will be deployed and an image built from it. +A certain set of environment variables must be defined in a json file and referenced as shown below in the build example. + +Replace UPPERCASE variables with your values. +```json +{ + "source_image": "OPENSTACK_SOURCE_IMAGE_ID", + "networks": "OPENSTACK_NETWORK_ID", + "flavor": "OPENSTACK_INSTANCE_FLAVOR_NAME", + "floating_ip_network": "OPENSTACK_FLOATING_IP_NETWORK_NAME", + "image_name": "KUBE-UBUNTU", + "image_visibility": "public", + "image_disk_format": "raw", + "volume_type": "", + "ssh_username": "ubuntu" +} +``` + +Check out `images/capi/packer/openstack/packer.json` for more variables such as allowing the use of floating IPs and config drives. + +### Building Image on OpenStack + +From the `images/capi` directory, run `PACKER_VAR_FILES=var_file.json make build-openstack-`. + +An instance is built in OpenStack from the source image defined. Once completed, the instance is shut down and the image is created. +This image will default to private, however this can be controlled via `image_visibility`. + +For building a ubuntu 22.04-based CAPI image with Kubernetes 1.23.15, run the following commands: + +#### Example +```bash +$ git clone https://github.com/kubernetes-sigs/image-builder.git +$ cd image-builder/images/capi/ +$ make deps-openstack +$ PACKER_VAR_FILES=var_file.json make build-openstack-ubuntu-2204 +``` + +The resulting image will be named `ubuntu-2204-kube-v1.23.15` based on the following format: `-kube-`. + +This can be modified by overriding the `image_name` variable if required. diff --git a/images/capi/Makefile b/images/capi/Makefile index 09680bdd28..fae61436b3 100644 --- a/images/capi/Makefile +++ b/images/capi/Makefile @@ -48,7 +48,7 @@ version: ## Display version of image-builder .PHONY: deps deps: ## Installs/checks all dependencies -deps: deps-ami deps-azure deps-do deps-gce deps-ova deps-qemu deps-raw deps-oci deps-osc deps-vbox deps-powervs deps-nutanix +deps: deps-ami deps-azure deps-do deps-gce deps-ova deps-openstack deps-qemu deps-raw deps-oci deps-osc deps-vbox deps-powervs deps-nutanix .PHONY: deps-ami deps-ami: ## Installs/checks dependencies for AMI builds @@ -81,7 +81,7 @@ deps-osc: hack/ensure-packer.sh hack/ensure-goss.sh packer plugins install github.com/outscale/outscale - + .PHONY: deps-gce deps-gce: ## Installs/checks dependencies for GCE builds deps-gce: @@ -98,6 +98,13 @@ deps-ova: hack/ensure-goss.sh hack/ensure-ovftool.sh +.PHONY: deps-openstack +deps-openstack: ## Installs/checks dependencies for OpenStack builds +deps-openstack: + hack/ensure-ansible.sh + hack/ensure-packer.sh + hack/ensure-goss.sh + .PHONY: deps-qemu deps-qemu: ## Installs/checks dependencies for QEMU builds deps-qemu: @@ -327,6 +334,8 @@ OCI_BUILD_NAMES ?= oci-ubuntu-1804 oci-ubuntu-2004 oci-ubuntu-2204 oci-orac DO_BUILD_NAMES ?= do-centos-7 do-ubuntu-1804 do-ubuntu-2004 +OPENSTACK_BUILD_NAMES ?= openstack-ubuntu-2004 openstack-ubuntu-2204 openstack-flatcar + OSC_BUILD_NAMES ?= osc-ubuntu-2004 QEMU_BUILD_NAMES ?= qemu-ubuntu-1804 qemu-ubuntu-2004 qemu-ubuntu-2204 qemu-centos-7 qemu-ubuntu-2004-efi qemu-rhel-8 qemu-rockylinux-8 qemu-flatcar @@ -361,6 +370,8 @@ AZURE_VALIDATE_SIG_TARGETS := $(addprefix validate-,$(AZURE_BUILD_SIG_NAMES)) AZURE_VALIDATE_SIG_GEN2_TARGETS := $(addprefix validate-,$(AZURE_BUILD_SIG_GEN2_NAMES)) DO_BUILD_TARGETS := $(addprefix build-,$(DO_BUILD_NAMES)) DO_VALIDATE_TARGETS := $(addprefix validate-,$(DO_BUILD_NAMES)) +OPENSTACK_BUILD_TARGETS := $(addprefix build-,$(OPENSTACK_BUILD_NAMES)) +OPENSTACK_VALIDATE_TARGETS := $(addprefix validate-,$(OPENSTACK_BUILD_NAMES)) QEMU_BUILD_TARGETS := $(addprefix build-,$(QEMU_BUILD_NAMES)) QEMU_VALIDATE_TARGETS := $(addprefix validate-,$(QEMU_BUILD_NAMES)) QEMU_KUBEVIRT_BUILD_TARGETS := $(addprefix build-,$(QEMU_KUBEVIRT_BUILD_NAMES)) @@ -460,6 +471,14 @@ $(DO_BUILD_TARGETS): deps-do $(DO_VALIDATE_TARGETS): deps-do packer validate $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/digitalocean/$(subst validate-do-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/digitalocean/packer.json +.PHONY: $(OPENSTACK_BUILD_TARGETS) +$(OPENSTACK_BUILD_TARGETS): deps-openstack + packer build $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/openstack/$(subst build-openstack-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/openstack/packer.json + +.PHONY: $(OPENSTACK_VALIDATE_TARGETS) +$(OPENSTACK_VALIDATE_TARGETS): deps-openstack + packer validate $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/openstack/$(subst validate-openstack-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/openstack/packer.json + .PHONY: $(QEMU_BUILD_TARGETS) $(QEMU_BUILD_TARGETS): deps-qemu packer build $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/qemu/$(subst build-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/qemu/packer.json @@ -495,7 +514,7 @@ $(OCI_VALIDATE_TARGETS): deps-oci packer validate $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/oci/$(subst validate-oci-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/oci/packer.json .PHONY: $(OSC_BUILD_TARGETS) -$(OSC_BUILD_TARGETS): deps-osc +$(OSC_BUILD_TARGETS): deps-osc packer build $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/outscale/$(subst build-osc-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/outscale/packer.json .PHONY: $(OSC_VALIDATE_TARGETS) @@ -673,6 +692,11 @@ build-node-ova-local-base-rockylinux-8: ## Builds RockyLinux 8 Base Node OVA w l build-node-ova-local-base-ubuntu-1804: ## Builds Ubuntu 18.04 Base Node OVA w local hypervisor build-node-ova-local-base-ubuntu-2004: ## Builds Ubuntu 20.04 Base Node OVA w local hypervisor +build-openstack-ubuntu-2004: ## Builds Ubuntu 20.04 OpenStack image +build-openstack-ubuntu-2204: ## Builds Ubuntu 22.04 OpenStack image +build-openstack-flatcar: ## Builds Flatcar OpenStack image +build-openstack-all: $(OPENSTACK_BUILD_TARGETS) + build-qemu-flatcar: ## Builds Flatcar QEMU image build-qemu-ubuntu-1804: ## Builds Ubuntu 18.04 QEMU image build-qemu-ubuntu-2004: ## Builds Ubuntu 20.04 QEMU image @@ -757,6 +781,11 @@ validate-do-ubuntu-2004: ## Validates Ubuntu 20.04 DigitalOcean Snapshot Packer validate-do-centos-7: ## Validates Centos 7 DigitalOcean Snapshot Packer config validate-do-all: $(DO_VALIDATE_TARGETS) ## Validates all DigitalOcean Snapshot Packer config +validate-openstack-ubuntu-2004: ## Validates Ubuntu 18.04 Openstack Image Packer config +validate-openstack-ubuntu-2204: ## Validates Ubuntu 20.04 Openstack Image Packer config +validate-openstack-flatcar: ## Validates Flatcar Openstack Image Packer config +validate-openstack-all: $(OPENSTACK_VALIDATE_TARGETS) ## Validates all Openstack Glance Image Packer config + validate-gce-ubuntu-1804: ## Validates Ubuntu 18.04 GCE Snapshot Packer config validate-gce-ubuntu-2004: ## Validates Ubuntu 20.04 GCE Snapshot Packer config validate-gce-ubuntu-2204: ## Validates Ubuntu 22.04 GCE Snapshot Packer config diff --git a/images/capi/ansible/roles/providers/tasks/main.yml b/images/capi/ansible/roles/providers/tasks/main.yml index a6ac551f0d..28c6091773 100644 --- a/images/capi/ansible/roles/providers/tasks/main.yml +++ b/images/capi/ansible/roles/providers/tasks/main.yml @@ -28,6 +28,9 @@ - include_tasks: googlecompute.yml when: packer_builder_type.startswith('googlecompute') +- include_tasks: openstack.yml + when: packer_builder_type.startswith('openstack') + - include_tasks: oci.yml when: packer_builder_type.startswith('oracle-oci') diff --git a/images/capi/ansible/roles/providers/tasks/openstack.yml b/images/capi/ansible/roles/providers/tasks/openstack.yml new file mode 100644 index 0000000000..485d93aa7a --- /dev/null +++ b/images/capi/ansible/roles/providers/tasks/openstack.yml @@ -0,0 +1,33 @@ +# Copyright 2020 The Kubernetes Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +--- +- name: Install cloud-init packages + apt: + name: "{{ packages }}" + state: present + force_apt_get: yes + vars: + packages: + - cloud-init + - cloud-guest-utils + - cloud-initramfs-copymods + - cloud-initramfs-dyn-netconf + when: ansible_os_family == "Debian" + +- name: Disable Hyper-V KVP protocol daemon on Ubuntu + systemd: + name: hv-kvp-daemon + state: stopped + enabled: false + when: ansible_os_family == "Debian" diff --git a/images/capi/packer/openstack/OWNERS b/images/capi/packer/openstack/OWNERS new file mode 100644 index 0000000000..8eebf84b76 --- /dev/null +++ b/images/capi/packer/openstack/OWNERS @@ -0,0 +1,9 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - cluster-api-openstack-maintainers + +reviewers: + - cluster-api-openstack-maintainers + - image-builder-openstack-reviewers + - image-builder-openstack-maintainers diff --git a/images/capi/packer/openstack/flatcar.json b/images/capi/packer/openstack/flatcar.json new file mode 100644 index 0000000000..2c63585d1b --- /dev/null +++ b/images/capi/packer/openstack/flatcar.json @@ -0,0 +1,12 @@ +{ + "ansible_extra_vars": "ansible_python_interpreter=/opt/bin/python", + "build_name": "flatcar", + "crictl_source_type": "http", + "distro_name": "flatcar", + "kubernetes_cni_source_type": "http", + "kubernetes_source_type": "http", + "source_image": "flatcar", + "systemd_prefix": "/etc/systemd", + "sysusr_prefix": "/opt", + "sysusrlocal_prefix": "/opt" +} diff --git a/images/capi/packer/openstack/packer.json b/images/capi/packer/openstack/packer.json new file mode 100644 index 0000000000..f8f6dcf16e --- /dev/null +++ b/images/capi/packer/openstack/packer.json @@ -0,0 +1,136 @@ +{ + "builders": [ + { + "config_drive": "{{user `attach_config_drive`}}", + "flavor": "{{user `flavor`}}", + "floating_ip_network": "{{user `floating_ip_network`}}", + "image_disk_format": "{{user `image_disk_format`}}", + "image_name": "{{user `image_name`}}", + "image_tags": "{{user `image_tags`}}", + "image_visibility": "{{user `image_visibility`}}", + "instance_name": "{{user `instance_name`}}", + "networks": "{{user `networks`}}", + "security_groups": "{{user `security_groups`}}", + "source_image": "{{user `source_image`}}", + "ssh_keypair_name": "{{user `ssh_keypair_name`}}", + "ssh_private_key_file": "{{user `ssh_private_key_file`}}", + "ssh_timeout": "2h", + "ssh_username": "{{user `ssh_username`}}", + "type": "openstack", + "use_blockstorage_volume": "{{user `use_blockstorage_volume`}}", + "use_floating_ip": "{{user `use_floating_ip`}}", + "volume_size": "{{user `volume_size`}}", + "volume_type": "{{user `volume_type`}}" + } + ], + "post-processors": [ + { + "environment_vars": [ + "CUSTOM_POST_PROCESSOR={{user `custom_post_processor`}}" + ], + "inline": [ + "if [ \"$CUSTOM_POST_PROCESSOR\" != \"true\" ]; then exit 0; fi", + "{{user `custom_post_processor_command`}}" + ], + "name": "custom-post-processor", + "type": "shell-local" + } + ], + "provisioners": [ + { + "execute_command": "BUILD_NAME={{user `build_name`}}; if [[ \"${BUILD_NAME}\" == *\"flatcar\"* ]]; then sudo {{.Vars}} -S -E bash '{{.Path}}'; fi", + "script": "./packer/files/flatcar/scripts/bootstrap-flatcar.sh", + "type": "shell" + }, + { + "ansible_env_vars": [ + "ANSIBLE_SSH_ARGS='{{user `existing_ansible_ssh_args`}} {{user `ansible_common_ssh_args`}}'" + ], + "extra_arguments": [ + "--scp-extra-args", + "{{user `ansible_scp_extra_args`}}", + "--extra-vars", + "{{user `ansible_common_vars`}}", + "--extra-vars", + "{{user `ansible_extra_vars`}}", + "--extra-vars", + "{{user `ansible_user_vars`}}" + ], + "playbook_file": "./ansible/node.yml", + "type": "ansible", + "user": "core" + }, + { + "arch": "{{user `goss_arch`}}", + "format": "{{user `goss_format`}}", + "format_options": "{{user `goss_format_options`}}", + "goss_file": "{{user `goss_entry_file`}}", + "inspect": "{{user `goss_inspect_mode`}}", + "tests": [ + "{{user `goss_tests_dir`}}" + ], + "type": "goss", + "url": "{{user `goss_url`}}", + "use_sudo": true, + "vars_file": "{{user `goss_vars_file`}}", + "vars_inline": { + "ARCH": "amd64", + "OS": "{{user `distro_name` | lower}}", + "OS_VERSION": "{{user `os_version`}}", + "PROVIDER": "qemu", + "containerd_version": "{{user `containerd_version`}}", + "kubernetes_cni_deb_version": "{{ user `kubernetes_cni_deb_version` }}", + "kubernetes_cni_rpm_version": "{{ split (user `kubernetes_cni_rpm_version`) \"-\" 0 }}", + "kubernetes_cni_source_type": "{{user `kubernetes_cni_source_type`}}", + "kubernetes_cni_version": "{{user `kubernetes_cni_semver` | replace \"v\" \"\" 1}}", + "kubernetes_deb_version": "{{ user `kubernetes_deb_version` }}", + "kubernetes_rpm_version": "{{ split (user `kubernetes_rpm_version`) \"-\" 0 }}", + "kubernetes_source_type": "{{user `kubernetes_source_type`}}", + "kubernetes_version": "{{user `kubernetes_semver` | replace \"v\" \"\" 1}}" + }, + "version": "{{user `goss_version`}}" + } + ], + "variables": { + "ansible_common_vars": "ansible_python_interpreter=/usr/bin/python3", + "ansible_extra_vars": "", + "ansible_user_vars": "", + "attach_config_drive": "false", + "build_timestamp": "{{timestamp}}", + "containerd_sha256": null, + "containerd_url": "https://github.com/containerd/containerd/releases/download/v{{user `containerd_version`}}/cri-containerd-cni-{{user `containerd_version`}}-linux-amd64.tar.gz", + "containerd_version": null, + "crictl_url": "https://github.com/kubernetes-sigs/cri-tools/releases/download/v{{user `crictl_version`}}/crictl-v{{user `crictl_version`}}-linux-amd64.tar.gz", + "crictl_version": null, + "existing_ansible_ssh_args": "{{env `ANSIBLE_SSH_ARGS`}}", + "floating_ip_network": "public", + "image_disk_format": "qcow2", + "image_name": "{{user `build_name`}}-kube-{{user `kubernetes_semver`}}", + "image_tags": "k8s,capi", + "image_visibility": "private", + "instance_name": "{{user `image_name` | replace_all \".\" \"-\"}}", + "kubernetes_cni_deb_version": null, + "kubernetes_cni_http_source": null, + "kubernetes_cni_semver": null, + "kubernetes_cni_source_type": null, + "kubernetes_container_registry": null, + "kubernetes_deb_gpg_key": null, + "kubernetes_deb_repo": null, + "kubernetes_deb_version": null, + "kubernetes_http_source": null, + "kubernetes_load_additional_imgs": null, + "kubernetes_rpm_gpg_check": null, + "kubernetes_rpm_gpg_key": null, + "kubernetes_rpm_repo": null, + "kubernetes_rpm_version": null, + "kubernetes_semver": null, + "kubernetes_series": null, + "kubernetes_source_type": null, + "security_groups": "default", + "ssh_username": "{{user `ssh_username`}}", + "use_blockstorage_volume": "true", + "use_floating_ip": "true", + "volume_size": "10", + "volume_type": null + } +} diff --git a/images/capi/packer/openstack/ubuntu-2004.json b/images/capi/packer/openstack/ubuntu-2004.json new file mode 100644 index 0000000000..9b221611fe --- /dev/null +++ b/images/capi/packer/openstack/ubuntu-2004.json @@ -0,0 +1,5 @@ +{ + "build_name": "ubuntu-2004", + "distro_name": "ubuntu", + "ssh_username": "ubuntu" +} diff --git a/images/capi/packer/openstack/ubuntu-2204.json b/images/capi/packer/openstack/ubuntu-2204.json new file mode 100644 index 0000000000..b520ea994a --- /dev/null +++ b/images/capi/packer/openstack/ubuntu-2204.json @@ -0,0 +1,5 @@ +{ + "build_name": "ubuntu-2204", + "distro_name": "ubuntu", + "ssh_username": "ubuntu" +}