| 1 | #!/usr/bin/env bash
|
| 2 | #
|
| 3 | # Usage:
|
| 4 | # regtest/aports-container.sh <function name>
|
| 5 |
|
| 6 | : ${LIB_OSH=stdlib/osh}
|
| 7 | source $LIB_OSH/bash-strict.sh
|
| 8 | source $LIB_OSH/task-five.sh
|
| 9 |
|
| 10 | source regtest/aports-common.sh
|
| 11 |
|
| 12 | # Flow
|
| 13 | #
|
| 14 | # - make-chroot
|
| 15 | # - add-build-deps - extra packages
|
| 16 | # - config-chroot - users/groups, keygen
|
| 17 | # - oils-in-chroot - can this be bind mount?
|
| 18 | # - save-default-config
|
| 19 | # - hm maybe we can use LAYERS here - baseline and osh
|
| 20 | #
|
| 21 | # - fetch-packages
|
| 22 | # - this can be another layer
|
| 23 | # - build-packages, which yields TSV and logs
|
| 24 | # - do we use podman cp?
|
| 25 | # - or do we set up a bind mount, and aports-guest.sh knows how to write
|
| 26 | # there?
|
| 27 | # - /home/udu/oils/_tmp/aports-guest could be the bind mount
|
| 28 | # - back to _tmp/aports-guest
|
| 29 | #
|
| 30 | # - and then we can push to a central registry?
|
| 31 | # - packages are 6 GB, so I guess we can take advantage of that
|
| 32 | #
|
| 33 | # TODO:
|
| 34 | # - test abuild rootbld
|
| 35 |
|
| 36 |
|
| 37 | deps() {
|
| 38 | # https://blog.abysm.org/2023/06/switching-system-wide-default-storage-driver-from-vfs-to-overlayfs-for-podman-on-debian-bookworm/
|
| 39 |
|
| 40 | # containers-storage needed on Debian bookworm for overlayfs
|
| 41 |
|
| 42 | sudo apt-get install podman containers-storage
|
| 43 | }
|
| 44 |
|
| 45 | system-reset() {
|
| 46 | # this removes everything
|
| 47 | podman system reset
|
| 48 | }
|
| 49 |
|
| 50 | system-prune() {
|
| 51 | # this is GC - it sorta works
|
| 52 | podman system prune -a
|
| 53 | }
|
| 54 |
|
| 55 | show-work-area() {
|
| 56 | # 16K files, each layer is already materialized
|
| 57 |
|
| 58 | # Hm the container is 277 M
|
| 59 | # But this work dir is 580 M , after podman system reset?
|
| 60 | # It's doubling the storage?
|
| 61 | # Because it's the VFS driver? Geez
|
| 62 | # for rootless operation
|
| 63 |
|
| 64 | local work_dir=~/.local/share/containers/storage/
|
| 65 |
|
| 66 | set +o errexit
|
| 67 | find $work_dir | wc -l
|
| 68 |
|
| 69 | du --si -s $work_dir
|
| 70 | }
|
| 71 |
|
| 72 | remove-all() {
|
| 73 | # It's silly that podman/docker have a separate set of commands
|
| 74 | # this should just be removing files!
|
| 75 |
|
| 76 | podman rmi -a -f
|
| 77 | }
|
| 78 |
|
| 79 | check-kernel-module() {
|
| 80 | lsmod | grep overlay
|
| 81 | }
|
| 82 |
|
| 83 | migrate() {
|
| 84 | # not sure if we need this
|
| 85 | podman system migrate
|
| 86 | }
|
| 87 |
|
| 88 | readonly branch='v3.22'
|
| 89 | readonly ROOTFS_TAR=_chroot/alpine-$branch.tar.gz
|
| 90 |
|
| 91 | make-rootfs() {
|
| 92 | rm -f -v $ROOTFS_TAR
|
| 93 |
|
| 94 | # apk-tools needed to bootstrap? otherwise we can't apk add later
|
| 95 | sudo ../../alpinelinux/alpine-make-rootfs/alpine-make-rootfs \
|
| 96 | --branch $branch \
|
| 97 | --packages 'apk-tools' \
|
| 98 | $ROOTFS_TAR
|
| 99 | }
|
| 100 |
|
| 101 | list-tar() {
|
| 102 | tar --list -z < $ROOTFS_TAR
|
| 103 | echo
|
| 104 |
|
| 105 | ls -l --si $ROOTFS_TAR
|
| 106 | }
|
| 107 |
|
| 108 | # copied from /etc/profile in the chroot
|
| 109 | readonly GUEST_PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
| 110 |
|
| 111 | make-oci() {
|
| 112 | ### make OCI image with buildah
|
| 113 | # there is also the pure hsell 'sloci-image' from Alpine
|
| 114 |
|
| 115 | set -x
|
| 116 |
|
| 117 | # Create a new container from scratch
|
| 118 | echo "Creating container from rootfs..."
|
| 119 | c1=$(buildah from scratch)
|
| 120 | echo "Container ID: $c1"
|
| 121 |
|
| 122 | # Add the rootfs directory contents to the container
|
| 123 | echo "Adding rootfs contents..."
|
| 124 | buildah add $c1 _chroot/alpine-v3.22.tar.gz /
|
| 125 |
|
| 126 | # Optional: Set environment variables
|
| 127 | # TODO: check this path, where does it come from?
|
| 128 | buildah config --env PATH=$GUEST_PATH $c1
|
| 129 |
|
| 130 | # Set some basic container metadata (optional but recommended)
|
| 131 | buildah config --workingdir /home/oils $c1
|
| 132 | buildah config --cmd /bin/sh $c1
|
| 133 |
|
| 134 | # copied from regtest/aports-setup.sh
|
| 135 | buildah run $c1 -- adduser -D udu
|
| 136 | buildah run $c1 -- addgroup udu abuild
|
| 137 | buildah run $c1 -- addgroup udu wheel
|
| 138 | buildah run $c1 -- sh -c \
|
| 139 | 'echo "permit nopass :wheel" >> /etc/doas.conf'
|
| 140 |
|
| 141 | buildah config --user udu $c1
|
| 142 |
|
| 143 | # Create the /app/data directory in the container
|
| 144 | #buildah run $c1 -- mkdir -p /home/oils
|
| 145 |
|
| 146 | # Commit the container to create an image
|
| 147 | IMAGE_NAME='aports-build:latest'
|
| 148 | echo "Committing container to image: $IMAGE_NAME"
|
| 149 | buildah commit $c1 $IMAGE_NAME
|
| 150 |
|
| 151 | # necessary for 2 layers
|
| 152 | local c2
|
| 153 | c2=$(buildah from $IMAGE_NAME)
|
| 154 |
|
| 155 | # Defaults from alpine-chroot-install
|
| 156 | buildah run --user root $c2 -- \
|
| 157 | apk add build-base ca-certificates ssl_client alpine-sdk abuild-rootbld pigz doas
|
| 158 |
|
| 159 | # Run as udu
|
| 160 | buildah run $c2 -- \
|
| 161 | abuild-keygen --append --install -n
|
| 162 |
|
| 163 | buildah commit $c2 $IMAGE_NAME
|
| 164 |
|
| 165 | # Hm this seems necessary to clean up the work area? Why?
|
| 166 | # system-prune also works, but it's a bad interface!
|
| 167 | #
|
| 168 | # I don't see why buildah does this extra copying ...
|
| 169 |
|
| 170 | #buildah rm $c2
|
| 171 |
|
| 172 | echo "Image built successfully: $IMAGE_NAME c1=$c1 c2=$c2"
|
| 173 | }
|
| 174 |
|
| 175 |
|
| 176 | run() {
|
| 177 | # Run the container with podman (rootless) and bind mount a dir
|
| 178 |
|
| 179 | # Make sure the host directory exists
|
| 180 | local host_dir=_tmp/mnt/data
|
| 181 | mkdir -p $host_dir
|
| 182 | touch $host_dir/foo.txt
|
| 183 |
|
| 184 | # Run the container with bind mount
|
| 185 | # --rm: remove container when it exits
|
| 186 | # -it: interactive with tty
|
| 187 | # -v: bind mount (volume)
|
| 188 | #
|
| 189 | # takes ~213 to ~275 ms to run
|
| 190 |
|
| 191 | # -v accepts :ro or :rw for mount options
|
| 192 | # also :z :Z selinux stuff
|
| 193 |
|
| 194 | local script='
|
| 195 | echo hi
|
| 196 | whoami
|
| 197 | pwd
|
| 198 | ls -l /
|
| 199 | echo
|
| 200 | ls -l /app/data
|
| 201 | echo
|
| 202 | apk list
|
| 203 |
|
| 204 | #ping www.google.com
|
| 205 | nslookup google.com
|
| 206 | echo
|
| 207 |
|
| 208 | ip addr show
|
| 209 | echo
|
| 210 |
|
| 211 | #ping host.containers.internal
|
| 212 | #echo
|
| 213 |
|
| 214 | #ping www.google.com
|
| 215 |
|
| 216 | nc google.com 80 <<"EOF"
|
| 217 | GET /
|
| 218 | EOF
|
| 219 | '
|
| 220 |
|
| 221 | local script='
|
| 222 | #ls -l /home/udu/aports/main
|
| 223 |
|
| 224 | whoami
|
| 225 | pwd
|
| 226 |
|
| 227 | abuild -f -r -C ~/aports/main/lua5.4 rootbld
|
| 228 | '
|
| 229 | # --userns=keep-id for mounts
|
| 230 | time podman run --rm -it \
|
| 231 | --privileged \
|
| 232 | --userns=keep-id \
|
| 233 | -v "$PWD/_tmp/mnt/data:/app/data:ro" \
|
| 234 | -v "$PWD/../../alpinelinux/aports/main:/home/udu/aports/main:rw" \
|
| 235 | aports-build:latest \
|
| 236 | sh -c "$script"
|
| 237 |
|
| 238 | }
|
| 239 |
|
| 240 | save() {
|
| 241 | local tar=_tmp/aports-oci.tar
|
| 242 | rm -f -v $tar
|
| 243 | podman save -o $tar aports-build:latest
|
| 244 | }
|
| 245 |
|
| 246 | extract-saved() {
|
| 247 | local tar=_tmp/aports-oci.tar
|
| 248 |
|
| 249 | tar --list < _tmp/aports-oci.tar
|
| 250 | echo
|
| 251 |
|
| 252 | ls -l --si $tar
|
| 253 |
|
| 254 | local tmp=_tmp/aports-oci
|
| 255 | rm -r -f $tmp
|
| 256 | mkdir -p $tmp
|
| 257 | pushd $tmp
|
| 258 | tar -x < ../aports-oci.tar
|
| 259 | popd
|
| 260 | }
|
| 261 |
|
| 262 | show-saved() {
|
| 263 | tree -h _tmp/aports-oci
|
| 264 | }
|
| 265 |
|
| 266 | list() {
|
| 267 | podman images | grep aports-build
|
| 268 | }
|
| 269 |
|
| 270 | test-rootless-overlay() {
|
| 271 | # AH, this works with --mount! Cool!
|
| 272 |
|
| 273 | unshare --user --map-root-user --mount -- bash -c '
|
| 274 | dir=_tmp/overlay-test
|
| 275 | mkdir -p $dir/{lower,upper,work,merged}
|
| 276 | echo "lower" > $dir/lower/foo
|
| 277 |
|
| 278 | # Try to mount as regular user
|
| 279 | #
|
| 280 | # permission denied
|
| 281 | # how does podman do it? Test it out
|
| 282 |
|
| 283 | mount -t overlay overlay \
|
| 284 | -o lowerdir=$dir/lower,upperdir=$dir/upper,workdir=$dir/work \
|
| 285 | $dir/merged
|
| 286 |
|
| 287 | echo MERGED
|
| 288 | ls -l $dir/merged
|
| 289 | echo "modify" > $dir/merged/foo
|
| 290 | cat $dir/merged/foo
|
| 291 |
|
| 292 | tree $dir
|
| 293 |
|
| 294 | echo LOWER
|
| 295 | cat $dir/lower/foo
|
| 296 | echo
|
| 297 |
|
| 298 | echo UPPER
|
| 299 | cat $dir/upper/foo
|
| 300 | echo
|
| 301 | '
|
| 302 | }
|
| 303 |
|
| 304 | task-five "$@"
|