aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Buchholz <tomalok@gmail.com>2018-08-27 22:26:28 -0700
committerMike Crute <mike@crute.us>2018-08-28 09:20:48 -0700
commit95b7837c9fc2b070bc9e44da1f6fdc0987eabf75 (patch)
treedeb48b1283462997d4039f641ff8a2af44057133
parent356105f23d0dc8cc50e629624892b223f209de37 (diff)
downloadalpine-ec2-ami-95b7837c9fc2b070bc9e44da1f6fdc0987eabf75.tar.bz2
alpine-ec2-ami-95b7837c9fc2b070bc9e44da1f6fdc0987eabf75.tar.xz
alpine-ec2-ami-95b7837c9fc2b070bc9e44da1f6fdc0987eabf75.zip
PR updates
* README.md + update list of modern instance types + add caveat regarding linux-vanilla vs. linux-virt * alpine-ami.yaml + build instance type is always t3.nano + block device where we build is always /dev/xvdf + add optional AMI encryption + always enable AMI SR-IOV flag (vanilla & virt both have the necessary driver) + no need to pass volume_name to make_ami.sh * make_ami.sh + replace hard tabs with 4 spaces + always set up edge repositories + no need to add mkinitfs package, it's a dependency of linux-* + fix update of /etc/inittab + fix configuration of NTP + declare local vars in main() + device is always /dev/xvdf * variables.json-default/example + improve comment for kernel_flavor + default add_repos is now empty + remove acct & e2fsprogs-extra from add_pkgs + add optional AMI encryption + remove sriov_enable, build_instance_type, and volume_name vars
-rw-r--r--README.md13
-rw-r--r--alpine-ami.yaml13
-rwxr-xr-xmake_ami.sh423
-rw-r--r--variables.json-default10
-rw-r--r--variables.json-example43
5 files changed, 254 insertions, 248 deletions
diff --git a/README.md b/README.md
index 462899c..10a1322 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,8 @@ containing Alpine Linux. The AMI is designed to work with most EC2 features
8such as Elastic Network Adapters and NVME EBS volumes by default. If anything 8such as Elastic Network Adapters and NVME EBS volumes by default. If anything
9is missing please report a bug. 9is missing please report a bug.
10 10
11This image can be launched on any modern instance type. Including T2, M5, C5, 11This image can be launched on any modern instance type, including T3, M5, C5,
12I3, R4, P2, P3, X1, X1e, D2. Other instances may also work but have not been 12I3, R5, P3, X1, X1e, D2, Z1d. Other instances may also work but have not been
13tested. If you find an issue with instance support for any current generation 13tested. If you find an issue with instance support for any current generation
14instance please file a bug against this project. 14instance please file a bug against this project.
15 15
@@ -50,10 +50,15 @@ its development and thus there are some sharp edges.
50 hardware so it seems unlikely that they will be supported going forward. Thus 50 hardware so it seems unlikely that they will be supported going forward. Thus
51 this project does not support them. 51 this project does not support them.
52 52
53- The linux-vanilla kernel all the linux-firmware packages it installs is much
54 larger than is necessary for an AMI designed to run on EC2. Unfortunately,
55 the linux-virt kernel is currently missing NVMe support, which is required for
56 the newest generation of instance families.
57
53- The aws-ena-driver-vanilla package is still in edge/testing, and requires the 58- The aws-ena-driver-vanilla package is still in edge/testing, and requires the
54 matching linux-vanilla package from edge/main. When ENA is available in an 59 matching linux-vanilla package from edge/main. When ENA is available in an
55 alpine version release, edge/testing and edge/main should no longer be 60 alpine version release (ideally with a 'virt' kernel flavor), edge/testing
56 necessary. 61 and edge/main should no longer be necessary.
57 62
58- [cloud-init](https://cloudinit.readthedocs.io/en/latest/) is not currently 63- [cloud-init](https://cloudinit.readthedocs.io/en/latest/) is not currently
59 supported on Alpine Linux. Instead this image uses 64 supported on Alpine Linux. Instead this image uses
diff --git a/alpine-ami.yaml b/alpine-ami.yaml
index bc39b89..09e0c4d 100644
--- a/alpine-ami.yaml
+++ b/alpine-ami.yaml
@@ -1,6 +1,6 @@
1variables: 1variables:
2 2
3 # NOTE: Additional configuration is set via the `variables.json` file. 3 # NOTE: Configuration is done with a `variables.json` file.
4 # To use default values, simply `cp variables.json-default variables.json`. 4 # To use default values, simply `cp variables.json-default variables.json`.
5 # See `variables.json-example` for full configuration variable descriptions. 5 # See `variables.json-example` for full configuration variable descriptions.
6 6
@@ -17,11 +17,11 @@ builders:
17 vpc_id: "{{user `vpc`}}" 17 vpc_id: "{{user `vpc`}}"
18 subnet_id: "{{user `subnet`}}" 18 subnet_id: "{{user `subnet`}}"
19 security_group_id: "{{user `security_group`}}" 19 security_group_id: "{{user `security_group`}}"
20 instance_type: "{{user `build_instance_type`}}" 20 instance_type: "t3.nano"
21 associate_public_ip_address: "{{user `public_ip`}}" 21 associate_public_ip_address: "{{user `public_ip`}}"
22 launch_block_device_mappings: 22 launch_block_device_mappings:
23 - volume_type: "gp2" 23 - volume_type: "gp2"
24 device_name: "{{user `volume_name`}}" 24 device_name: "/dev/xvdf"
25 delete_on_termination: "true" 25 delete_on_termination: "true"
26 volume_size: "{{user `volume_size`}}" 26 volume_size: "{{user `volume_size`}}"
27 ssh_username: "ec2-user" 27 ssh_username: "ec2-user"
@@ -42,13 +42,14 @@ builders:
42 ami_description: "{{user `ami_desc_prefix`}}{{user `alpine_release`}}-r{{user `ami_release`}}{{user `ami_desc_suffix`}}" 42 ami_description: "{{user `ami_desc_prefix`}}{{user `alpine_release`}}-r{{user `ami_release`}}{{user `ami_desc_suffix`}}"
43 ami_virtualization_type: "hvm" 43 ami_virtualization_type: "hvm"
44 ami_root_device: 44 ami_root_device:
45 source_device_name: "{{user `volume_name`}}" 45 source_device_name: "/dev/xvdf"
46 device_name: "/dev/xvda" 46 device_name: "/dev/xvda"
47 delete_on_termination: "true" 47 delete_on_termination: "true"
48 volume_size: "{{user `volume_size`}}" 48 volume_size: "{{user `volume_size`}}"
49 volume_type: "gp2" 49 volume_type: "gp2"
50 encrypt_boot: "{{user `encrypt_ami`}}"
50 ena_support: "{{user `ena_enable`}}" 51 ena_support: "{{user `ena_enable`}}"
51 sriov_support: "{{user `sriov_enable`}}" 52 sriov_support: "true"
52 ami_groups: "{{user `ami_access`}}" 53 ami_groups: "{{user `ami_access`}}"
53 ami_regions: "{{user `deploy_regions`}}" 54 ami_regions: "{{user `deploy_regions`}}"
54 55
@@ -56,4 +57,4 @@ builders:
56provisioners: 57provisioners:
57 - type: "shell" 58 - type: "shell"
58 script: "make_ami.sh" 59 script: "make_ami.sh"
59 execute_command: 'sudo sh -c "{{ .Vars }} {{ .Path }} {{user `volume_name`}} {{user `kernel_flavor`}} ''{{user `add_repos`}}'' ''{{user `add_pkgs`}}''"' 60 execute_command: 'sudo sh -c "{{ .Vars }} {{ .Path }} {{user `kernel_flavor`}} ''{{user `add_repos`}}'' ''{{user `add_pkgs`}}''"'
diff --git a/make_ami.sh b/make_ami.sh
index 2917445..6218694 100755
--- a/make_ami.sh
+++ b/make_ami.sh
@@ -1,5 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# vim: set ts=4 noet: 2# vim: set ts=4 et:
3 3
4set -eu 4set -eu
5 5
@@ -10,308 +10,309 @@ set -eu
10: ${ALPINE_KEYS_SHA256:="f7832b848cedca482b145011cf516e82392f02a10713875cb09f39c7221c6f17"} 10: ${ALPINE_KEYS_SHA256:="f7832b848cedca482b145011cf516e82392f02a10713875cb09f39c7221c6f17"}
11 11
12die() { 12die() {
13 printf '\033[1;31mERROR:\033[0m %s\n' "$@" >&2 # bold red 13 printf '\033[1;31mERROR:\033[0m %s\n' "$@" >&2 # bold red
14 exit 1 14 exit 1
15} 15}
16 16
17einfo() { 17einfo() {
18 printf '\n\033[1;36m> %s\033[0m\n' "$@" >&2 # bold cyan 18 printf '\n\033[1;36m> %s\033[0m\n' "$@" >&2 # bold cyan
19} 19}
20 20
21rc_add() { 21rc_add() {
22 local target="$1"; shift # target directory 22 local target="$1"; shift # target directory
23 local runlevel="$1"; shift # runlevel name 23 local runlevel="$1"; shift # runlevel name
24 local services="$*" # names of services 24 local services="$*" # names of services
25 25
26 local svc; for svc in $services; do 26 local svc; for svc in $services; do
27 mkdir -p "$target"/etc/runlevels/$runlevel 27 mkdir -p "$target"/etc/runlevels/$runlevel
28 ln -s /etc/init.d/$svc "$target"/etc/runlevels/$runlevel/$svc 28 ln -s /etc/init.d/$svc "$target"/etc/runlevels/$runlevel/$svc
29 echo " * service $svc added to runlevel $runlevel" 29 echo " * service $svc added to runlevel $runlevel"
30 done 30 done
31} 31}
32 32
33wgets() ( 33wgets() (
34 local url="$1" # url to fetch 34 local url="$1" # url to fetch
35 local sha256="$2" # expected SHA256 sum of output 35 local sha256="$2" # expected SHA256 sum of output
36 local dest="$3" # output path and filename 36 local dest="$3" # output path and filename
37 37
38 wget -T 10 -q -O "$dest" "$url" 38 wget -T 10 -q -O "$dest" "$url"
39 echo "$sha256 $dest" | sha256sum -c > /dev/null 39 echo "$sha256 $dest" | sha256sum -c > /dev/null
40) 40)
41 41
42 42
43validate_block_device() { 43validate_block_device() {
44 local dev="$1" # target directory 44 local dev="$1" # target directory
45 45
46 lsblk -P --fs "$dev" >/dev/null 2>&1 || \ 46 lsblk -P --fs "$dev" >/dev/null 2>&1 || \
47 die "'$dev' is not a valid block device" 47 die "'$dev' is not a valid block device"
48 48
49 if lsblk -P --fs "$dev" | grep -vq 'FSTYPE=""'; then 49 if lsblk -P --fs "$dev" | grep -vq 'FSTYPE=""'; then
50 die "Block device '$dev' is not blank" 50 die "Block device '$dev' is not blank"
51 fi 51 fi
52} 52}
53 53
54fetch_apk_tools() { 54fetch_apk_tools() {
55 local store="$(mktemp -d)" 55 local store="$(mktemp -d)"
56 local tarball="$(basename $APK_TOOLS_URI)" 56 local tarball="$(basename $APK_TOOLS_URI)"
57 57
58 wgets "$APK_TOOLS_URI" "$APK_TOOLS_SHA256" "$store/$tarball" 58 wgets "$APK_TOOLS_URI" "$APK_TOOLS_SHA256" "$store/$tarball"
59 tar -C "$store" -xf "$store/$tarball" 59 tar -C "$store" -xf "$store/$tarball"
60 60
61 find "$store" -name apk 61 find "$store" -name apk
62} 62}
63 63
64make_filesystem() { 64make_filesystem() {
65 local device="$1" # target device path 65 local device="$1" # target device path
66 local target="$2" # mount target 66 local target="$2" # mount target
67 67
68 mkfs.ext4 "$device" 68 mkfs.ext4 "$device"
69 e2label "$device" / 69 e2label "$device" /
70 mount "$device" "$target" 70 mount "$device" "$target"
71} 71}
72 72
73setup_repositories() { 73setup_repositories() {
74 local target="$1" # target directory 74 local target="$1" # target directory
75 local add_repos="$2" # extra repo lines, comma separated 75 local add_repos="$2" # extra repo lines, comma separated
76 76
77 mkdir -p "$target"/etc/apk/keys 77 mkdir -p "$target"/etc/apk/keys
78 cat > "$target"/etc/apk/repositories <<-EOF 78 cat > "$target"/etc/apk/repositories <<EOF
79 http://dl-cdn.alpinelinux.org/alpine/v$ALPINE_RELEASE/main 79http://dl-cdn.alpinelinux.org/alpine/v$ALPINE_RELEASE/main
80 http://dl-cdn.alpinelinux.org/alpine/v$ALPINE_RELEASE/community 80http://dl-cdn.alpinelinux.org/alpine/v$ALPINE_RELEASE/community
81 EOF 81@edge-main http://dl-cdn.alpinelinux.org/alpine/edge/main
82 echo "$add_repos" | tr , "\012" >> "$target"/etc/apk/repositories 82@edge-community http://dl-cdn.alpinelinux.org/alpine/edge/community
83@edge-testing http://dl-cdn.alpinelinux.org/alpine/edge/testing
84EOF
85 echo "$add_repos" | tr , "\012" >> "$target"/etc/apk/repositories
83} 86}
84 87
85fetch_keys() { 88fetch_keys() {
86 local target="$1" 89 local target="$1"
87 local tmp="$(mktemp -d)" 90 local tmp="$(mktemp -d)"
88 91
89 wgets "$ALPINE_KEYS" "$ALPINE_KEYS_SHA256" "$tmp/alpine-keys.apk" 92 wgets "$ALPINE_KEYS" "$ALPINE_KEYS_SHA256" "$tmp/alpine-keys.apk"
90 tar -C "$target" -xvf "$tmp"/alpine-keys.apk etc/apk/keys 93 tar -C "$target" -xvf "$tmp"/alpine-keys.apk etc/apk/keys
91 rm -rf "$tmp" 94 rm -rf "$tmp"
92} 95}
93 96
94setup_chroot() { 97setup_chroot() {
95 local target="$1" 98 local target="$1"
96 99
97 mount -t proc none "$target"/proc 100 mount -t proc none "$target"/proc
98 mount --bind /dev "$target"/dev 101 mount --bind /dev "$target"/dev
99 mount --bind /sys "$target"/sys 102 mount --bind /sys "$target"/sys
100 103
101 # Don't want to ship this but it's needed for bootstrap. Will be removed in 104 # Don't want to ship this but it's needed for bootstrap. Will be removed in
102 # the cleanup stage. 105 # the cleanup stage.
103 install -Dm644 /etc/resolv.conf "$target"/etc/resolv.conf 106 install -Dm644 /etc/resolv.conf "$target"/etc/resolv.conf
104} 107}
105 108
106install_core_packages() { 109install_core_packages() {
107 local target="$1" # target directory 110 local target="$1" # target directory
108 local flavor="$2" # kernel flavor 111 local flavor="$2" # kernel flavor
109 local add_pkgs="$3" # extra packages, space separated 112 local add_pkgs="$3" # extra packages, space separated
110 113
111 # Most from: https://git.alpinelinux.org/cgit/alpine-iso/tree/alpine-virt.packages 114 # Most from: https://git.alpinelinux.org/cgit/alpine-iso/tree/alpine-virt.packages
112 # 115 #
113 # linux-$flavor - linux kernel flavor to install 116 # sudo - to allow alpine user to become root, disallow root SSH logins
114 # e2fsprogs - required by init scripts to maintain ext4 volumes 117 # tiny-ec2-bootstrap - to bootstrap system from EC2 metadata
115 # mkinitfs - required to build custom initfs 118 #
116 # sudo - to allow alpine user to become root, disallow root SSH logins 119 chroot "$target" apk --no-cache add \
117 # tiny-ec2-bootstrap - to bootstrap system from EC2 metadata 120 linux-"$flavor" \
118 chroot "$target" apk --no-cache add \ 121 alpine-mirrors \
119 linux-"$flavor" \ 122 chrony \
120 alpine-mirrors \ 123 e2fsprogs \
121 chrony \ 124 openssh \
122 e2fsprogs \ 125 sudo \
123 mkinitfs \ 126 tiny-ec2-bootstrap \
124 openssh \ 127 tzdata \
125 sudo \ 128 $add_pkgs
126 tiny-ec2-bootstrap \ 129
127 tzdata \ 130 chroot "$target" apk --no-cache add --no-scripts syslinux
128 $add_pkgs 131
129 132 # Disable starting getty for physical ttys because they're all inaccessible
130 chroot "$target" apk --no-cache add --no-scripts syslinux 133 # anyhow. With this configuration boot messages will still display in the
131 134 # EC2 console.
132 # Disable starting getty for physical ttys because they're all inaccessible 135 sed -Ei '/^tty[0-9]/s/^/#/' \
133 # anyhow. With this configuration boot messages will still display in the 136 "$target"/etc/inittab
134 # EC2 console. 137
135 sed -Ei '/^tty\d/s/^/#/' "$target"/etc/inittab 138 # Make it a little more obvious who is logged in by adding username to the
136 139 # prompt
137 # Make it a little more obvious who is logged in by adding username to the 140 sed -i "s/^export PS1='/&\\\\u@/" "$target"/etc/profile
138 # prompt
139 sed -i "s/^export PS1='/&\\\\u@/" "$target"/etc/profile
140} 141}
141 142
142create_initfs() { 143create_initfs() {
143 local target="$1" 144 local target="$1"
144 145
145 # Create ENA feature for mkinitfs 146 # Create ENA feature for mkinitfs
146 echo "kernel/drivers/net/ethernet/amazon" > \ 147 echo "kernel/drivers/net/ethernet/amazon" > \
147 "$target"/etc/mkinitfs/features.d/ena.modules 148 "$target"/etc/mkinitfs/features.d/ena.modules
148 149
149 # Enable ENA and NVME features these don't hurt for any instance and are 150 # Enable ENA and NVME features these don't hurt for any instance and are
150 # hard requirements of the 5 series and i3 series of instances 151 # hard requirements of the 5 series and i3 series of instances
151 sed -Ei 's/^features="([^"]+)"/features="\1 nvme ena"/' \ 152 sed -Ei 's/^features="([^"]+)"/features="\1 nvme ena"/' \
152 "$target"/etc/mkinitfs/mkinitfs.conf 153 "$target"/etc/mkinitfs/mkinitfs.conf
153 154
154 chroot "$target" /sbin/mkinitfs $(basename $(find "$target"/lib/modules/* -maxdepth 0)) 155 chroot "$target" /sbin/mkinitfs $(basename $(find "$target"/lib/modules/* -maxdepth 0))
155} 156}
156 157
157setup_extlinux() { 158setup_extlinux() {
158 local target="$1" 159 local target="$1"
159 160
160 # Must use disk labels instead of UUID or devices paths so that this works 161 # Must use disk labels instead of UUID or devices paths so that this works
161 # across instance familes. UUID works for many instances but breaks on the 162 # across instance familes. UUID works for many instances but breaks on the
162 # NVME ones because EBS volumes are hidden behind NVME devices. 163 # NVME ones because EBS volumes are hidden behind NVME devices.
163 # 164 #
164 # Enable ext4 because the root device is formatted ext4 165 # Enable ext4 because the root device is formatted ext4
165 # 166 #
166 # Shorten timeout because EC2 has no way to interact with instance console 167 # Shorten timeout because EC2 has no way to interact with instance console
167 # 168 #
168 # ttyS0 is the target for EC2s "Get System Log" feature whereas tty0 is the 169 # ttyS0 is the target for EC2s "Get System Log" feature whereas tty0 is the
169 # target for EC2s "Get Instance Screenshot" feature. Enabling the serial 170 # target for EC2s "Get Instance Screenshot" feature. Enabling the serial
170 # port early in extlinux gives the most complete output in the system log. 171 # port early in extlinux gives the most complete output in the system log.
171 sed -Ei -e "s|^[# ]*(root)=.*|\1=LABEL=/|" \ 172 sed -Ei -e "s|^[# ]*(root)=.*|\1=LABEL=/|" \
172 -e "s|^[# ]*(default_kernel_opts)=.*|\1=\"console=ttyS0 console=tty0\"|" \ 173 -e "s|^[# ]*(default_kernel_opts)=.*|\1=\"console=ttyS0 console=tty0\"|" \
173 -e "s|^[# ]*(serial_port)=.*|\1=ttyS0|" \ 174 -e "s|^[# ]*(serial_port)=.*|\1=ttyS0|" \
174 -e "s|^[# ]*(modules)=.*|\1=sd-mod,usb-storage,ext4|" \ 175 -e "s|^[# ]*(modules)=.*|\1=sd-mod,usb-storage,ext4|" \
175 -e "s|^[# ]*(default)=.*|\1=hardened|" \ 176 -e "s|^[# ]*(default)=.*|\1=hardened|" \
176 -e "s|^[# ]*(timeout)=.*|\1=1|" \ 177 -e "s|^[# ]*(timeout)=.*|\1=1|" \
177 "$target"/etc/update-extlinux.conf 178 "$target"/etc/update-extlinux.conf
178} 179}
179 180
180install_extlinux() { 181install_extlinux() {
181 local target="$1" 182 local target="$1"
182 183
183 chroot "$target" /sbin/extlinux --install /boot 184 chroot "$target" /sbin/extlinux --install /boot
184 chroot "$target" /sbin/update-extlinux --warn-only 185 chroot "$target" /sbin/update-extlinux --warn-only
185} 186}
186 187
187setup_fstab() { 188setup_fstab() {
188 local target="$1" 189 local target="$1"
189 190
190 cat > "$target"/etc/fstab <<-EOF 191 cat > "$target"/etc/fstab <<EOF
191 # <fs> <mountpoint> <type> <opts> <dump/pass> 192# <fs> <mountpoint> <type> <opts> <dump/pass>
192 LABEL=/ / ext4 defaults,noatime 1 1 193LABEL=/ / ext4 defaults,noatime 1 1
193 EOF 194EOF
194} 195}
195 196
196setup_networking() { 197setup_networking() {
197 local target="$1" 198 local target="$1"
198 199
199 cat > "$target"/etc/network/interfaces <<-EOF 200 cat > "$target"/etc/network/interfaces <<EOF
200 auto lo 201auto lo
201 iface lo inet loopback 202iface lo inet loopback
202 203
203 auto eth0 204auto eth0
204 iface eth0 inet dhcp 205iface eth0 inet dhcp
205 EOF 206EOF
206} 207}
207 208
208enable_services() { 209enable_services() {
209 local target="$1" 210 local target="$1"
210 211
211 rc_add "$target" default sshd chronyd networking tiny-ec2-bootstrap 212 rc_add "$target" default sshd chronyd networking tiny-ec2-bootstrap
212 rc_add "$target" sysinit devfs dmesg mdev hwdrivers 213 rc_add "$target" sysinit devfs dmesg mdev hwdrivers
213 rc_add "$target" boot modules hwclock swap hostname sysctl bootmisc syslog acpid 214 rc_add "$target" boot modules hwclock swap hostname sysctl bootmisc syslog acpid
214 rc_add "$target" shutdown killprocs savecache mount-ro 215 rc_add "$target" shutdown killprocs savecache mount-ro
215} 216}
216 217
217create_alpine_user() { 218create_alpine_user() {
218 local target="$1" 219 local target="$1"
219 220
220 # Allow members of the wheel group to sudo without a password. By default 221 # Allow members of the wheel group to sudo without a password. By default
221 # this will only be the alpine user. This allows us to ship an AMI that is 222 # this will only be the alpine user. This allows us to ship an AMI that is
222 # accessible via SSH using the user's configured SSH keys (thanks to 223 # accessible via SSH using the user's configured SSH keys (thanks to
223 # tiny-ec2-bootstrap) but does not allow remote root access which is the 224 # tiny-ec2-bootstrap) but does not allow remote root access which is the
224 # best-practice. 225 # best-practice.
225 sed -i '/%wheel .* NOPASSWD: .*/s/^# //' "$target"/etc/sudoers 226 sed -i '/%wheel .* NOPASSWD: .*/s/^# //' "$target"/etc/sudoers
226 227
227 # There is no real standard ec2 username across AMIs, Amazon uses ec2-user 228 # There is no real standard ec2 username across AMIs, Amazon uses ec2-user
228 # for their Amazon Linux AMIs but Ubuntu uses ubuntu, Fedora uses fedora, 229 # for their Amazon Linux AMIs but Ubuntu uses ubuntu, Fedora uses fedora,
229 # etc... (see: https://alestic.com/2014/01/ec2-ssh-username/). So our user 230 # etc... (see: https://alestic.com/2014/01/ec2-ssh-username/). So our user
230 # and group are alpine because this is Alpine Linux. On instance bootstrap 231 # and group are alpine because this is Alpine Linux. On instance bootstrap
231 # the user can create whatever users they want and delete this one. 232 # the user can create whatever users they want and delete this one.
232 chroot "$target" /usr/sbin/addgroup alpine 233 chroot "$target" /usr/sbin/addgroup alpine
233 chroot "$target" /usr/sbin/adduser -h /home/alpine -s /bin/sh -G alpine -D alpine 234 chroot "$target" /usr/sbin/adduser -h /home/alpine -s /bin/sh -G alpine -D alpine
234 chroot "$target" /usr/sbin/addgroup alpine wheel 235 chroot "$target" /usr/sbin/addgroup alpine wheel
235 chroot "$target" /usr/bin/passwd -u alpine 236 chroot "$target" /usr/bin/passwd -u alpine
236} 237}
237 238
238configure_ntp() { 239configure_ntp() {
239 local target="$1" 240 local target="$1"
240 241
241 # EC2 provides an instance-local NTP service syncronized with GPS and 242 # EC2 provides an instance-local NTP service syncronized with GPS and
242 # atomic clocks in-region. Prefer this over external NTP hosts when running 243 # atomic clocks in-region. Prefer this over external NTP hosts when running
243 # in EC2. 244 # in EC2.
244 # 245 #
245 # See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/set-time.html 246 # See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/set-time.html
246 sed -i 's/^server .*/server 169.254.169.123/' "$target"/etc/chrony/chrony.conf 247 sed -i 's/^pool .*/server 169.254.169.123 iburst/' "$target"/etc/chrony/chrony.conf
247} 248}
248 249
249cleanup() { 250cleanup() {
250 local target="$1" 251 local target="$1"
251 252
252 # Sweep cruft out of the image that doesn't need to ship or will be 253 # Sweep cruft out of the image that doesn't need to ship or will be
253 # re-generated when the image boots 254 # re-generated when the image boots
254 rm -f \ 255 rm -f \
255 "$target"/var/cache/apk/* \ 256 "$target"/var/cache/apk/* \
256 "$target"/etc/resolv.conf \ 257 "$target"/etc/resolv.conf \
257 "$target"/root/.ash_history \ 258 "$target"/root/.ash_history \
258 "$target"/etc/*- 259 "$target"/etc/*-
259 260
260 umount \ 261 umount \
261 "$target"/dev \ 262 "$target"/dev \
262 "$target"/proc \ 263 "$target"/proc \
263 "$target"/sys 264 "$target"/sys
264 265
265 umount "$target" 266 umount "$target"
266} 267}
267 268
268main() { 269main() {
269 [ "$#" -ne 4 ] && { echo "usage: $0 <block-device> <kernel-flavor> '<repo>[,<repo>]' '<pkg>[ <pkg>]'"; exit 1; } 270 [ "$#" -ne 3 ] && { echo "usage: $0 <kernel-flavor> '<repo>[,<repo>]' '<pkg>[ <pkg>]'"; exit 1; }
270 271
271 device="$1" 272 local flavor="$1"
272 flavor="$2" 273 local add_repos="$2"
273 add_repos="$3" 274 local add_pkgs="$3"
274 add_pkgs="$4"
275 275
276 target="/mnt/target" 276 local device="/dev/xvdf"
277 local target="/mnt/target"
277 278
278 validate_block_device "$device" 279 validate_block_device "$device"
279 280
280 [ -d "$target" ] || mkdir "$target" 281 [ -d "$target" ] || mkdir "$target"
281 282
282 einfo "Fetching static APK tools" 283 einfo "Fetching static APK tools"
283 apk="$(fetch_apk_tools)" 284 apk="$(fetch_apk_tools)"
284 285
285 einfo "Creating root filesystem" 286 einfo "Creating root filesystem"
286 make_filesystem "$device" "$target" 287 make_filesystem "$device" "$target"
287 288
288 setup_repositories "$target" "$add_repos" 289 setup_repositories "$target" "$add_repos"
289 290
290 einfo "Fetching Alpine signing keys" 291 einfo "Fetching Alpine signing keys"
291 fetch_keys "$target" 292 fetch_keys "$target"
292 293
293 einfo "Installing base system" 294 einfo "Installing base system"
294 $apk add --root "$target" --update-cache --initdb alpine-base 295 $apk add --root "$target" --update-cache --initdb alpine-base
295 296
296 setup_chroot "$target" 297 setup_chroot "$target"
297 298
298 einfo "Installing core packages" 299 einfo "Installing core packages"
299 install_core_packages "$target" "$flavor" "$add_pkgs" 300 install_core_packages "$target" "$flavor" "$add_pkgs"
300 301
301 einfo "Configuring and enabling boot loader" 302 einfo "Configuring and enabling boot loader"
302 create_initfs "$target" 303 create_initfs "$target"
303 setup_extlinux "$target" 304 setup_extlinux "$target"
304 install_extlinux "$target" 305 install_extlinux "$target"
305 306
306 einfo "Configuring system" 307 einfo "Configuring system"
307 setup_fstab "$target" 308 setup_fstab "$target"
308 setup_networking "$target" 309 setup_networking "$target"
309 enable_services "$target" 310 enable_services "$target"
310 create_alpine_user "$target" 311 create_alpine_user "$target"
311 configure_ntp "$target" 312 configure_ntp "$target"
312 313
313 einfo "All done, cleaning up" 314 einfo "All done, cleaning up"
314 cleanup "$target" 315 cleanup "$target"
315} 316}
316 317
317main "$@" 318main "$@"
diff --git a/variables.json-default b/variables.json-default
index c82e111..d45378f 100644
--- a/variables.json-default
+++ b/variables.json-default
@@ -5,18 +5,16 @@
5 "ami_desc_prefix": "Alpine Linux ", 5 "ami_desc_prefix": "Alpine Linux ",
6 "ami_desc_suffix": " Release with EC2 Optimizations", 6 "ami_desc_suffix": " Release with EC2 Optimizations",
7 "kernel_flavor": "vanilla@edge-main", 7 "kernel_flavor": "vanilla@edge-main",
8 "add_repos": "@edge-main http://dl-cdn.alpinelinux.org/alpine/edge/main,@edge-testing http://dl-cdn.alpinelinux.org/alpine/edge/testing", 8 "add_repos": "",
9 "add_pkgs": "acct aws-ena-driver-vanilla@edge-testing e2fsprogs-extra", 9 "add_pkgs": "aws-ena-driver-vanilla@edge-testing",
10 "ena_enable": "true", 10 "ena_enable": "true",
11 "sriov_enable": "false",
12 "volume_size": "1", 11 "volume_size": "1",
12 "encrypt_ami": "false",
13 "ami_access": "all", 13 "ami_access": "all",
14 "deploy_regions": "us-east-1,us-east-2,us-west-1,us-west-2,ca-central-1,eu-central-1,eu-west-1,eu-west-2,eu-west-3,ap-northeast-1,ap-northeast-2,ap-southeast-1,ap-southeast-2,ap-south-1,sa-east-1", 14 "deploy_regions": "us-east-1,us-east-2,us-west-1,us-west-2,ca-central-1,eu-central-1,eu-west-1,eu-west-2,eu-west-3,ap-northeast-1,ap-northeast-2,ap-southeast-1,ap-southeast-2,ap-south-1,sa-east-1",
15 15
16 "vpc": "", 16 "vpc": "",
17 "subnet": "", 17 "subnet": "",
18 "security_group": "", 18 "security_group": "",
19 "public_ip": "false", 19 "public_ip": "false"
20 "build_instance_type": "t2.nano",
21 "volume_name": "/dev/xvdf"
22} 20}
diff --git a/variables.json-example b/variables.json-example
index c422de5..0e10c9a 100644
--- a/variables.json-example
+++ b/variables.json-example
@@ -1,4 +1,5 @@
1# NOTE: This is file not valid JSON. 1# *** NOTE: This is file not valid JSON! ***
2
2{ 3{
3 ### Build Options ### 4 ### Build Options ###
4 5
@@ -13,31 +14,37 @@
13 "ami_desc_prefix": "Alpine Linux ", 14 "ami_desc_prefix": "Alpine Linux ",
14 "ami_desc_suffix": " Release with EC2 Optimizations", 15 "ami_desc_suffix": " Release with EC2 Optimizations",
15 16
16 # Kernel "flavor" to install. 'virt' is a slim choice, but doesn't currently 17 # Kernel "flavor" to install.
17 # include NVME support and there is no matching 'aws-ena-driver' package. 18 #
19 # 'virt' is the slim choice, but doesn't currently include NVMe support and
20 # there is no matching 'aws-ena-driver' package. When these features are
21 # available, this kernel flavor will be the default (if not hardcoded).
22 #
18 # 'vanilla' installs a lot of unneeded stuff (for an AMI), but does support 23 # 'vanilla' installs a lot of unneeded stuff (for an AMI), but does support
19 # NVME; however, there is no matching ENA driver in the main repo. In order 24 # NVMe; however, there is no matching ENA driver in the main repo. In order
20 # to support NVME and ENA, we need to use 'vanilla@edge-main', which matches 25 # to support NVMe and ENA, we need to use 'vanilla@edge-main', which matches
21 # the 'aws-ena-driver@edge-testing' package. 26 # the 'aws-ena-driver@edge-testing' package.
27 #
22 "kernel_flavor": "vanilla@edge-main", 28 "kernel_flavor": "vanilla@edge-main",
23 29
24 # Comma separated list of lines to add to /etc/apk/repositories. We need 30 # Comma separated list of custom lines to add to /etc/apk/repositories.
25 # edge/main and edge/testing for simultaneous NVME and ENA support. 31 # @edge-main, @edge-community, and @edge-testing repos have been predefined.
26 "add_repos": "@edge-main http://dl-cdn.alpinelinux.org/alpine/edge/main,@edge-testing http://dl-cdn.alpinelinux.org/alpine/edge/testing", 32 "add_repos": "",
27 33
28 # Space separated list of additional packages to add to the AMI. 34 # Space separated list of additional packages to add to the AMI.
29 # acct - system accounting utilities (sa, etc.) 35 # aws-ena-driver-vanilla - ENA driver (until we have a 'virt' flavor)
30 # aws-ena-driver-vanilla - Enhanced Network Adapter kernel module 36 "add_pkgs": "aws-ena-driver-vanilla@edge-testing",
31 # e2fsprogs-extra - ec2-tiny-bootstrap's currently undeclared dependency (resize2fs)
32 "add_pkgs": "acct aws-ena-driver-vanilla@edge-testing e2fsprogs-extra",
33 37
34 # Enable ENA/SRIOV support on the AMI. 38 # Enable ENA support on the AMI.
39 # When ENA is available for the 'virt' kernel, this will always be on.
35 "ena_enable": "true", 40 "ena_enable": "true",
36 "sriov_enable": "false",
37 41
38 # Size of the AMI image (in GiB). 42 # Size of the AMI image (in GiB).
39 "volume_size": "1", 43 "volume_size": "1",
40 44
45 # Encrypt the AMI?
46 "encrypt_ami": "false",
47
41 # Comma separated list of groups that should have access to the AMI. However, 48 # Comma separated list of groups that should have access to the AMI. However,
42 # only two values are currently supported: 'all' for public, '' for private. 49 # only two values are currently supported: 'all' for public, '' for private.
43 "ami_access": "all", 50 "ami_access": "all",
@@ -62,12 +69,6 @@
62 # Assign a public IP to the builder instance. Set to 'true' for if you need 69 # Assign a public IP to the builder instance. Set to 'true' for if you need
63 # to initiate the build from somewhere that wouldn't normally be able to 70 # to initiate the build from somewhere that wouldn't normally be able to
64 # access the builder instance's private network. 71 # access the builder instance's private network.
65 "public_ip": "false", 72 "public_ip": "false"
66
67 # Instance type to use for building.
68 "build_instance_type": "t2.nano",
69 73
70 # Don't override this without a good reason, and if you do just make sure it
71 # gets passed all the way through to the make_ami script.
72 "volume_name": "/dev/xvdf"
73} 74}