3
# podman-registry - start/stop/monitor a local instance of registry:2
7
###############################################################################
10
PODMAN_REGISTRY_IMAGE=quay.io/libpod/registry:2.8
17
PODMAN=${PODMAN:-$(dirname $0)/../bin/podman}
20
###############################################################################
23
missing=" argument is missing; see $ME -h for details"
24
usage="Usage: $ME [options] [start|stop|ps|logs]
26
$ME manages a local instance of a container registry.
28
When called to start a registry, $ME will pull an image
29
into a local temporary directory, create an htpasswd, start the
30
registry, and dump a series of environment variables to stdout:
33
PODMAN_REGISTRY_IMAGE=\"docker.io/library/registry:2.8\"
34
PODMAN_REGISTRY_PORT=\"5050\"
35
PODMAN_REGISTRY_USER=\"userZ3RZ\"
36
PODMAN_REGISTRY_PASS=\"T8JVJzKrcl4p6uT\"
38
Expected usage, therefore, is something like this in a script
42
To stop the registry, you will need to know the port number:
44
$ME -P \$PODMAN_REGISTRY_PORT stop
46
Override the default image, port, user, password with:
48
-i IMAGE registry image to pull (default: $PODMAN_REGISTRY_IMAGE)
49
-u USER registry user (default: random)
50
-p PASS password for registry user (default: random)
51
-P PORT port to bind to (on 127.0.0.1) (default: random, 5000-5999)
55
-h display usage message
64
###############################################################################
65
# BEGIN option processing
67
while getopts "i:u:p:P:hv" opt; do
69
i) PODMAN_REGISTRY_IMAGE=$OPTARG ;;
70
u) PODMAN_REGISTRY_USER=$OPTARG ;;
71
p) PODMAN_REGISTRY_PASS=$OPTARG ;;
72
P) PODMAN_REGISTRY_PORT=$OPTARG ;;
73
h) echo "$usage"; exit 0;;
75
\?) echo "Run '$ME -h' for help" >&2; exit 1;;
80
# END option processing
81
###############################################################################
82
# BEGIN helper functions
84
function random_string() {
87
head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length
91
if [ -z "${PODMAN_REGISTRY_PORT}" ]; then
92
die "podman port undefined; please invoke me with -P PORT"
95
if [ -z "${PODMAN_REGISTRY_WORKDIR}" ]; then
96
PODMAN_REGISTRY_WORKDIR=${TMPDIR:-/tmp}/podman-registry-${PODMAN_REGISTRY_PORT}
97
if [ ! -d ${PODMAN_REGISTRY_WORKDIR} ]; then
98
die "$ME: directory does not exist: ${PODMAN_REGISTRY_WORKDIR}"
102
# Reset $PODMAN, so ps/logs/stop use same args as the initial start
103
PODMAN="$(<${PODMAN_REGISTRY_WORKDIR}/PODMAN)"
105
${PODMAN} --root ${PODMAN_REGISTRY_WORKDIR}/root \
106
--runroot ${PODMAN_REGISTRY_WORKDIR}/runroot \
111
# must_pass # Run a command quietly; abort with error on failure
113
function must_pass() {
114
local log=${PODMAN_REGISTRY_WORKDIR}/log
117
if [ $? -ne 0 ]; then
118
echo "$ME: Command failed: $*" >&2
121
# If we ever get here, it's a given that the registry is not running.
122
# Clean up after ourselves.
123
${PODMAN} unshare rm -rf ${PODMAN_REGISTRY_WORKDIR}
129
# wait_for_port # Returns once port is available on localhost
131
function wait_for_port() {
132
local port=$1 # Numeric port
138
while [ $_timeout -gt 0 ]; do
139
{ exec {unused_fd}<> /dev/tcp/$host/$port; } &>/dev/null && return
141
_timeout=$(( $_timeout - 1 ))
144
die "Timed out waiting for port $port"
147
# END helper functions
148
###############################################################################
149
# BEGIN action processing
152
# If called without a port, assign a random one in the 5xxx range
153
if [ -z "${PODMAN_REGISTRY_PORT}" ]; then
154
for port in $(shuf -i 5000-5999);do
155
if ! { exec {unused_fd}<> /dev/tcp/127.0.0.1/$port; } &>/dev/null; then
156
PODMAN_REGISTRY_PORT=$port
162
PODMAN_REGISTRY_WORKDIR=${TMPDIR:-/tmp}/podman-registry-${PODMAN_REGISTRY_PORT}
163
if [ -d ${PODMAN_REGISTRY_WORKDIR} ]; then
164
die "$ME: directory exists: ${PODMAN_REGISTRY_WORKDIR} (another registry might already be running on this port)"
167
# Randomly-generated username and password, if none given on command line
168
if [ -z "${PODMAN_REGISTRY_USER}" ]; then
169
PODMAN_REGISTRY_USER="user$(random_string 4)"
171
if [ -z "${PODMAN_REGISTRY_PASS}" ]; then
172
PODMAN_REGISTRY_PASS=$(random_string 15)
175
# For the next few commands, die on any error
178
mkdir -p ${PODMAN_REGISTRY_WORKDIR}
180
# Preserve initial podman path & args, so all subsequent invocations
181
# of this script are consistent with the first one.
182
echo "$PODMAN" >${PODMAN_REGISTRY_WORKDIR}/PODMAN
184
local AUTHDIR=${PODMAN_REGISTRY_WORKDIR}/auth
187
# Pull registry image, but into a separate container storage
188
mkdir -p ${PODMAN_REGISTRY_WORKDIR}/root
189
mkdir -p ${PODMAN_REGISTRY_WORKDIR}/runroot
193
# Give it three tries, to compensate for flakes
194
podman pull ${PODMAN_REGISTRY_IMAGE} &>/dev/null ||
195
podman pull ${PODMAN_REGISTRY_IMAGE} &>/dev/null ||
196
must_pass podman pull ${PODMAN_REGISTRY_IMAGE}
198
# Registry image needs a cert. Self-signed is good enough.
199
local CERT=$AUTHDIR/domain.crt
200
must_pass openssl req -newkey rsa:4096 -nodes -sha256 \
201
-keyout ${AUTHDIR}/domain.key -x509 -days 2 \
202
-out ${AUTHDIR}/domain.crt \
203
-subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=localhost"
205
# Store credentials where container will see them. We can't run
206
# this one via must_pass because we need its stdout.
207
htpasswd -Bbn ${PODMAN_REGISTRY_USER} ${PODMAN_REGISTRY_PASS} \
209
if [ $? -ne 0 ]; then
210
rm -rf ${PODMAN_REGISTRY_WORKDIR}
211
die "Command failed: htpasswd"
214
# In case someone needs to debug
215
echo "${PODMAN_REGISTRY_USER}:${PODMAN_REGISTRY_PASS}" \
216
> $AUTHDIR/htpasswd-plaintext
218
# Run the registry container.
219
must_pass podman run --quiet -d \
220
-p ${PODMAN_REGISTRY_PORT}:5000 \
222
-v $AUTHDIR:/auth:Z \
223
-e "REGISTRY_AUTH=htpasswd" \
224
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
225
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
226
-e "REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt" \
227
-e "REGISTRY_HTTP_TLS_KEY=/auth/domain.key" \
228
${PODMAN_REGISTRY_IMAGE}
230
# Confirm that registry started and port is active
231
wait_for_port $PODMAN_REGISTRY_PORT
233
# Dump settings. Our caller will use these to access the registry.
234
for v in IMAGE PORT USER PASS; do
235
echo "PODMAN_REGISTRY_${v}=\"$(eval echo \$PODMAN_REGISTRY_${v})\""
242
podman rm -f registry
244
# Use straight podman, not our alias function, to avoid 'overlay: EBUSY'
245
cmd="rm -rf ${PODMAN_REGISTRY_WORKDIR}"
246
if [[ $(id -u) -eq 0 ]]; then
249
${PODMAN} unshare $cmd
263
# END action processing
264
###############################################################################
265
# BEGIN command-line processing
267
# First command-line arg must be an action
268
action=${1?ACTION$missing}
276
*) die "Unknown action '$action'; must be start / stop / ps / logs" ;;
279
# END command-line processing
280
###############################################################################