mirror of
https://gitea.com/mcereda/oam.git
synced 2026-02-09 05:44:23 +00:00
274 lines
7.7 KiB
Markdown
274 lines
7.7 KiB
Markdown
# Cloud init
|
|
|
|
## Table of contents <!-- omit in toc -->
|
|
|
|
1. [TL;DR](#tldr)
|
|
1. [Merge 2 or more files or parts](#merge-2-or-more-files-or-parts)
|
|
1. [Further readings](#further-readings)
|
|
1. [Sources](#sources)
|
|
|
|
## TL;DR
|
|
|
|
```sh
|
|
# Get the current status.
|
|
cloud-init status
|
|
cloud-init status --wait
|
|
|
|
# Verify that cloud-init received the expected user data.
|
|
sudo cloud-init query userdata
|
|
sudo cat /var/lib/cloud/instance/user-data.txt | gunzip
|
|
|
|
# Assert the user data we provided is a valid cloud-config.
|
|
# A.K.A. validate files.
|
|
# Versions <22.2 require 'devel schema' instead of only 'schema'.
|
|
sudo cloud-init schema -c '/var/lib/cloud/instance/user-data.txt'
|
|
sudo cloud-init schema --system --annotate
|
|
|
|
# Check the user scripts.
|
|
ls '/var/lib/cloud/instance/scripts'
|
|
|
|
# Check the raw logs.
|
|
cat '/var/log/cloud-init-output.log'
|
|
tail -f '/var/log/cloud-init.log' '/var/log/cloud-init-output.log'
|
|
|
|
# Parse and organize the events in the log file by stage.
|
|
cloud-init analyze show
|
|
|
|
# Clean up everything so `cloud-init` can run again.
|
|
sudo cloud-init clean
|
|
|
|
# Re-run everything.
|
|
# 1. Clean the existing configuration.
|
|
# 2. Detect local data sources.
|
|
# 3. Detect any data source requiring the network and run the 'initialization' modules.
|
|
# 4. Run the 'configuration' modules.
|
|
# 5. Run the 'final' modules.
|
|
sudo cloud-init clean --logs \
|
|
&& sudo cloud-init init --local \
|
|
&& sudo cloud-init init \
|
|
&& sudo cloud-init modules --mode='config' \
|
|
&& sudo cloud-init modules -m 'final'
|
|
|
|
# Manually run a single cloud-config module once after the instance has booted.
|
|
# Requires one to delete the semaphores in /var/lib/cloud/instances/hostname/sem. Cloud-init will not re-run if these
|
|
# files are present.
|
|
sudo rm -fv '/var/lib/cloud/instances'/*/'sem/config_ssh' && sudo cloud-init single --name 'cc_ssh' --frequency 'always'
|
|
sudo rm -fv '/var/lib/cloud/instances'/*/'sem/config_write_files_deferred' \
|
|
&& sudo cloud-init single -n 'write_files_deferred' --frequency 'once'
|
|
```
|
|
|
|
```yaml
|
|
#cloud-config
|
|
|
|
# Add the Docker repository
|
|
yum_repos:
|
|
docker-ce:
|
|
name: Docker CE Stable - $basearch
|
|
enabled: true
|
|
baseurl: https://download.docker.com/linux/rhel/$releasever/$basearch/stable
|
|
priority: 1
|
|
gpgcheck: true
|
|
gpgkey: https://download.docker.com/linux/rhel/gpg
|
|
|
|
# Upgrade the instance
|
|
package_upgrade: true
|
|
package_reboot_if_required: true
|
|
|
|
# Install required packages
|
|
# docker-ce already depends on docker-ce-cli and containerd.io
|
|
packages:
|
|
- docker-ce
|
|
- jq
|
|
- unzip
|
|
|
|
# Enable and start the service after installation
|
|
runcmd:
|
|
- systemctl daemon-reload
|
|
- systemctl enable --now docker.service
|
|
```
|
|
|
|
## Merge 2 or more files or parts
|
|
|
|
See [Merging User-Data sections] for details.
|
|
|
|
```yaml
|
|
#cloud-config
|
|
packages:
|
|
- jq
|
|
- unzip
|
|
|
|
---
|
|
merge_how:
|
|
- name: list
|
|
settings: [append]
|
|
- name: dict
|
|
settings: [no_replace, recurse_list]
|
|
|
|
packages:
|
|
- parallel
|
|
|
|
---
|
|
packages:
|
|
- vim
|
|
|
|
merge_type: 'list(append)+dict(recurse_array)+str()'
|
|
```
|
|
|
|
<details>
|
|
<summary>In Pulumi</summary>
|
|
|
|
1. Create a data resource containing the files in order, one per part:
|
|
|
|
```ts
|
|
new cloudinit.Config("example", {
|
|
gzip: true,
|
|
base64Encode: true,
|
|
parts: [
|
|
{
|
|
contentType: "text/cloud-config",
|
|
content: fs.readFileSync("cloud-init/aws.ssm.yaml", "utf8"),
|
|
filename: "cloud-config.ssm.yml",
|
|
},
|
|
{
|
|
contentType: "text/cloud-config",
|
|
content: YAML.stringify({
|
|
number: 3,
|
|
plain: 'string',
|
|
block: 'two\nlines\n'
|
|
}),
|
|
filename: "cloud-config.inline.yml",
|
|
mergeType: "dict(recurse_array,no_replace)+list(append)",
|
|
},
|
|
{
|
|
contentType: "text/cloud-config",
|
|
content: pulumi.all([
|
|
certificate.certificateDomain.apply(v => v),
|
|
certificate.certificatePem.apply(v => v),
|
|
certificate.privateKeyPem.apply(v => v),
|
|
]).apply(([domain, certificate, privateKey]) => yaml.stringify({
|
|
write_files: [
|
|
{
|
|
path: `/etc/gitlab/ssl/${domain}.crt`,
|
|
content: certificate,
|
|
permissions: "0o600",
|
|
defer: true,
|
|
},
|
|
{
|
|
path: `/etc/gitlab/ssl/${domain}.key`,
|
|
content: btoa(privateKey),
|
|
permissions: "0o600",
|
|
encoding: "base64",
|
|
defer: true,
|
|
},
|
|
],
|
|
})),
|
|
filename: "letsencrypt.certificate.yml",
|
|
mergeType: "dict(recurse_array,no_replace)+list(append)",
|
|
},
|
|
],
|
|
});
|
|
```
|
|
|
|
1. Give its rendered form as input to a virtual machine's `userdata` attribute, or export it:
|
|
|
|
```ts
|
|
let userData = new cloudinit.Config("userData", { … });
|
|
new aws.ec2.Instance("instance", {
|
|
userData: userData.rendered,
|
|
…
|
|
})
|
|
```
|
|
|
|
</details>
|
|
<details>
|
|
<summary>In Terraform</summary>
|
|
|
|
1. Create a data resource containing the files in order, one per part:
|
|
|
|
```hcl
|
|
# https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs
|
|
# https://github.com/chrusty/terraform-multipart-userdata/blob/master/example/cloudinit.tf
|
|
data "cloudinit_config" "vm" {
|
|
gzip = true
|
|
base64_encode = true
|
|
|
|
part {
|
|
content = file("${path.module}/files/cloud-init/first.yaml")
|
|
content_type = "text/cloud-config"
|
|
filename = "first.yaml"
|
|
}
|
|
…
|
|
part {
|
|
content = templatefile(
|
|
"${path.module}/templates/cloud-init/n-th.yaml.tftpl",
|
|
{
|
|
key = value
|
|
}
|
|
)
|
|
content_type = "text/cloud-config"
|
|
merge_type = "dict(recurse_array,no_replace)+list(append)"
|
|
filename = "n-th.yaml"
|
|
}
|
|
}
|
|
```
|
|
|
|
1. Give its rendered form as input to a virtual machine's `userdata` attribute or an output resource:
|
|
|
|
```hcl
|
|
resource "azurerm_linux_virtual_machine" "vm" {
|
|
user_data = data.cloudinit_config.vm.rendered
|
|
…
|
|
}
|
|
|
|
output "cloudinit_config" {
|
|
value = data.cloudinit_config.vm.rendered
|
|
}
|
|
```
|
|
|
|
</details>
|
|
|
|
## Further readings
|
|
|
|
- [Website]
|
|
- [Modules]
|
|
- [Examples]
|
|
- [Merging User-Data sections]
|
|
- [cloud-init multipart encoding issues]
|
|
- [Test cloud-init with a multipass container]
|
|
- [Mime Multi Part Archive] format
|
|
- [Docker cloud init example]
|
|
|
|
### Sources
|
|
|
|
- [Debugging cloud-init]
|
|
- [Tutorial]
|
|
- [Cloud-Init configuration merging]
|
|
- [Terraform's cloud-init provider]
|
|
- [How to test cloud-init locally with Vagrant]
|
|
- [How to re-run cloud-init without reboot]
|
|
|
|
<!--
|
|
References
|
|
-->
|
|
|
|
<!-- In-article sections -->
|
|
<!-- Files -->
|
|
[docker cloud init example]: ../examples/cloud-init/docker.yum.yaml
|
|
|
|
<!-- Upstream -->
|
|
[debugging cloud-init]: https://docs.cloud-init.io/en/latest/howto/debugging.html
|
|
[examples]: https://docs.cloud-init.io/en/latest/reference/examples.html
|
|
[merging user-data sections]: https://docs.cloud-init.io/en/latest/reference/merging.html
|
|
[modules]: https://cloudinit.readthedocs.io/en/latest/topics/modules.html
|
|
[mime multi part archive]: https://cloudinit.readthedocs.io/en/latest/topics/format.html#mime-multi-part-archive
|
|
[tutorial]: https://docs.cloud-init.io/en/latest/tutorial/
|
|
[website]: https://cloud-init.io/
|
|
|
|
<!-- Others -->
|
|
[cloud-init configuration merging]: https://jen20.dev/post/cloudinit-configuration-merging/
|
|
[cloud-init multipart encoding issues]: https://github.com/hashicorp/terraform/issues/4794
|
|
[how to re-run cloud-init without reboot]: https://stackoverflow.com/questions/23065673/how-to-re-run-cloud-init-without-reboot#71152408
|
|
[how to test cloud-init locally with vagrant]: https://www.grzegorowski.com/how-to-test-cloud-init-locally-with-vagrant
|
|
[terraform's cloud-init provider]: https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs/data-sources/cloudinit_config
|
|
[test cloud-init with a multipass container]: https://medium.com/open-devops-academy/test-cloud-init-with-a-multipass-containers-e3e3bb740604
|