OILS / deps / images.sh View on Github | oilshell.org

270 lines, 125 significant
1#!/usr/bin/env bash
2#
3# Manage container images for Soil
4#
5# Usage:
6# deps/images.sh <function name>
7#
8# Example: Rebuild an image:
9#
10# (1) Update LATEST_TAG
11#
12# (2) Rebuild
13#
14# deps/images.sh build common # populates apt cache. WHY DO I NEED THIS?
15# deps/images.sh build cpp T # reuse package cache from apt-get
16# deps/images.sh smoke cpp
17#
18# (3) Push image and common
19#
20# deps/images.sh push cpp # pushes the LATEST_TAG
21#
22# deps/images.sh list-tagged # find hash of soil-common
23# sudo docker tag abcdef oilshell/soil-common:latest
24# deps/images.sh push common latest # update latest, for next Docker build
25#
26# (4) Update live version in 'soil/host-shim.sh live-image-tag'
27#
28# Our images:
29#
30# https://hub.docker.com/u/oilshell
31
32set -o nounset
33set -o pipefail
34set -o errexit
35
36source deps/podman.sh
37
38DOCKER=${DOCKER:-docker}
39
40# Build with this tag
41readonly LATEST_TAG='v-2023-10-05a'
42
43# BUGS in Docker.
44#
45# https://stackoverflow.com/questions/69173822/docker-build-uses-wrong-dockerfile-content-bug
46
47# NOTE: This also clears the exec.cachemount
48prune() {
49 sudo $DOCKER builder prune -f
50}
51
52# https://stackoverflow.com/questions/62834806/docker-buildkit-cache-location-size-and-id
53#
54# It lives somewhere in /var/lib/docker/overlay2
55
56show-cachemount() {
57 sudo $DOCKER system df -v --format '{{ .BuildCache | json }}' \
58 | jq '.[] | select(.CacheType == "exec.cachemount")' | tee _tmp/cachemount.txt
59
60 cat _tmp/cachemount.txt | jq -r '.ID' | while read id; do
61 sudo tree /var/lib/docker/overlay2/$id
62 sudo du --si -s /var/lib/docker/overlay2/$id
63 echo
64 done
65}
66
67tag-common() {
68 local hash=$1 # get hash from $0 list-tagged
69 sudo $DOCKER tag $hash oilshell/soil-common:latest
70}
71
72build() {
73 local name=${1:-dummy}
74 local use_cache=${2:-} # OFF by default
75
76 # set -x
77 local -a flags
78 if test -n "$use_cache"; then
79 flags=()
80 else
81 flags=('--no-cache=true')
82 fi
83 #flags+=('--progress=plain')
84
85 # Uh BuildKit is not the default on Linux!
86 # http://jpetazzo.github.io/2021/11/30/docker-build-container-images-antipatterns/
87 #
88 # It is more parallel and has colored output.
89
90 # TODO: use --authfile and more
91 #export-podman
92
93 # can't preserve the entire env: https://github.com/containers/buildah/issues/3887
94 #sudo --preserve-env=CONTAINERS_REGISTRIES_CONF --preserve-env=REGISTRY_AUTH_FILE \
95 sudo -E DOCKER_BUILDKIT=1 \
96 $DOCKER build "${flags[@]}" \
97 --tag "oilshell/soil-$name:$LATEST_TAG" \
98 --file deps/Dockerfile.$name .
99}
100
101list-images() {
102 for name in deps/Dockerfile.*; do
103 local image_id=${name//'deps/Dockerfile.'/}
104 if test "$image_id" = 'test-image'; then
105 continue
106 fi
107 echo $image_id
108 done
109}
110
111tag-all-latest() {
112 list-images | grep -v 'wedge-builder' | while read image; do
113 local tag
114 tag=$(soil/host-shim.sh live-image-tag $image)
115
116 echo "$tag $image"
117
118 # syntax: source -> target
119 sudo $DOCKER tag oilshell/soil-$image:$tag oilshell/soil-$image:latest
120 done
121}
122
123push-all-latest() {
124 ### 'latest' can lag behind the tagged version, so push to catch up
125
126 # because our 'my-sizes' script fetches the latest manifest
127
128 list-images | grep -v 'wedge-builder' | while read image_id; do
129 echo "___ $image_id"
130 push $image_id latest
131 done
132}
133
134list-tagged() {
135 sudo $DOCKER images 'oilshell/soil-*:v-*'
136}
137
138push() {
139 local name=${1:-dummy}
140 local tag=${2:-$LATEST_TAG}
141
142 # TODO: replace with flags
143 #export-podman
144
145 local image="oilshell/soil-$name:$tag"
146
147 # -E for export-podman vars
148 sudo -E $DOCKER push $image
149 #sudo -E $DOCKER --log-level=debug push $image
150}
151
152smoke() {
153 ### Smoke test of container
154 local name=${1:-dummy}
155 local tag=${2:-$LATEST_TAG}
156 local docker=${3:-$DOCKER}
157 local prefix=${4:-}
158
159 #sudo docker run oilshell/soil-$name
160 #sudo docker run oilshell/soil-$name python2 -c 'print("python2")'
161
162 # Need to point at registries.conf ?
163 #export-podman
164
165 sudo $docker run ${prefix}oilshell/soil-$name:$tag bash -c '
166echo "bash $BASH_VERSION"
167
168git --version
169
170for name in python python2 python3; do
171 if which $name; then
172 $name -V
173 else
174 echo "$name not found"
175 fi
176done
177'
178
179 # Python 2.7 build/prepare.sh requires this
180 #sudo docker run oilshell/soil-$name python -V
181
182 #sudo docker run oilshell/soil-$name python3 -c 'import pexpect; print(pexpect)'
183}
184
185smoke-podman() {
186 local name=${1:-dummy}
187
188 # need explicit docker.io prefix with podman
189 smoke $name latest podman docker.io/
190}
191
192cmd() {
193 ### Run an arbitrary command
194 local name=${1:-dummy}
195 local tag=${2:-$LATEST_TAG}
196
197 shift 2
198
199 sudo $DOCKER run oilshell/soil-$name:$tag "$@"
200}
201
202utf8() {
203 # needed for a spec test, not the default on Debian
204 cmd ovm-tarball bash -c 'LC_ALL=en_US.UTF-8; echo $LC_ALL'
205}
206
207mount-test() {
208 local name=${1:-dummy}
209
210 local -a argv
211 if test $# -le 1; then
212 argv=(sh -c 'ls -l /home/uke/oil')
213 else
214 argv=( "${@:2}" ) # index 2 not 1, weird shell behavior
215 fi
216
217 # mount Oil directory as /app
218 sudo $DOCKER run \
219 --mount "type=bind,source=$PWD,target=/home/uke/oil" \
220 oilshell/soil-$name "${argv[@]}"
221}
222
223image-history() {
224 local image_id=${1:-dummy}
225 local tag=${2:-latest}
226
227 local image="oilshell/soil-$image_id"
228
229 sudo $DOCKER history $image:$tag
230}
231
232save() {
233 local image_id=${1:-dummy}
234 local tag=${2:-latest}
235
236 local image="oilshell/soil-$image_id"
237
238 mkdir -p _tmp/images
239 local out=_tmp/images/$image_id.tar
240
241 # Use > instead of -o so it doesn'th have root permissions
242 time sudo $DOCKER save $image:$tag > $out
243 ls -l -h $out
244}
245
246# This shows CREATED, command CREATED BY, size
247# It's a human readable size though
248#
249# This doesn't really have anything better
250# https://gist.github.com/MichaelSimons/fb588539dcefd9b5fdf45ba04c302db6
251#
252# It's annoying that the remote registry API is different than the local API.
253
254layers() {
255 local name=${1:-dummy}
256 local tag=${2:-$LATEST_TAG}
257
258 local image="oilshell/soil-$name:$tag"
259
260 # Gah this still prints 237M, not the exact number of bytes!
261 # --format ' {{ .Size }} '
262 sudo $DOCKER history --no-trunc $image
263
264 echo $'Size\tVirtual Size'
265 sudo $DOCKER inspect $image \
266 | jq --raw-output '.[0] | [.Size, .VirtualSize] | @tsv' \
267 | commas
268}
269
270"$@"