-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker_aliases.sh
More file actions
478 lines (430 loc) · 14.2 KB
/
docker_aliases.sh
File metadata and controls
478 lines (430 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
#!/bin/bash
# Docker Compose Aliases — portable across all servers
# Source this file in .bashrc or .zshrc (compatible with both)
#
# Setup:
# 1. Place this file at ~/.docker_aliases.sh
# 2. Add to .bashrc or .zshrc: [[ -f ~/.docker_aliases.sh ]] && source ~/.docker_aliases.sh
# 3. Ensure your compose directory has a .env with COMPOSE_FILE set
#
# Features:
# - Works from any directory (no cd side effects)
# - Resolves 1Password op:// secrets only for commands that need them
# - Tab completion for service names (bash and zsh)
# - fzf integration for interactive service selection (optional)
# - Dozzle group management via container labels
# Auto-detect compose directory — customize these paths for your setup
if [[ -d "/opt/dockergit" ]] && [[ -f "/opt/dockergit/.env" ]]; then
DOCKER_GIT_DIR="/opt/dockergit"
elif [[ -d "$HOME/.docker" ]] && [[ -f "$HOME/.docker/.env" ]]; then
DOCKER_GIT_DIR="$HOME/.docker"
else
DOCKER_GIT_DIR=""
fi
# Colors
_dc_red() { printf '\033[0;31m%s\033[0m\n' "$1"; }
_dc_green() { printf '\033[0;32m%s\033[0m\n' "$1"; }
_dc_yellow() { printf '\033[0;33m%s\033[0m\n' "$1"; }
_dc_blue() { printf '\033[0;34m%s\033[0m\n' "$1"; }
# Initialize compose environment (no cd — uses --project-directory instead)
_dc_init() {
[[ -z "$DOCKER_GIT_DIR" ]] && { _dc_red "No compose directory found"; return 1; }
[[ -d "$DOCKER_GIT_DIR" ]] || { _dc_red "Directory not found: $DOCKER_GIT_DIR"; return 1; }
if [[ -z "$COMPOSE_FILE" ]] && [[ -f "$DOCKER_GIT_DIR/.env" ]]; then
local raw
raw=$(grep '^COMPOSE_FILE=' "$DOCKER_GIT_DIR/.env" 2>/dev/null | cut -d= -f2-)
# Convert relative paths to absolute (relative to DOCKER_GIT_DIR)
# Use tr+while to split on ':' (portable across bash and zsh)
local abs="" f
while IFS= read -r f || [[ -n "$f" ]]; do
[[ "$f" != /* ]] && f="$DOCKER_GIT_DIR/$f"
abs="${abs:+$abs:}$f"
done < <(printf '%s' "$raw" | tr ':' '\n')
export COMPOSE_FILE="$abs"
fi
}
# Commands that need op:// secrets resolved (container runtime)
_dc_needs_secrets() {
case "$1" in
up|exec|run|create) return 0 ;;
*) return 1 ;;
esac
}
# Plain docker compose with project directory
_dc_plain() {
docker compose --project-directory "$DOCKER_GIT_DIR" "$@"
}
# Compose wrapper — only uses op run for commands that need secrets
_dc_compose() {
if _dc_needs_secrets "$1" && command -v op &>/dev/null && grep -q 'op://' "$DOCKER_GIT_DIR/.env" 2>/dev/null; then
op run --env-file "$DOCKER_GIT_DIR/.env" -- docker compose --project-directory "$DOCKER_GIT_DIR" "$@"
else
_dc_plain "$@"
fi
}
# Wait for container to be healthy
_wait_healthy() {
local svc=$1 timeout=${2:-60}
_dc_blue "Waiting for $svc to be healthy (max ${timeout}s)..."
local status
for ((i=0; i<timeout; i++)); do
status=$(docker inspect --format='{{.State.Health.Status}}' "$svc" 2>/dev/null)
case "$status" in
healthy) _dc_green "$svc is healthy"; return 0 ;;
unhealthy) _dc_red "$svc is unhealthy"; return 1 ;;
esac
sleep 1
done
_dc_yellow "$svc health check timed out"
return 1
}
# Confirm destructive action (bash/zsh compatible)
_dc_confirm() {
local msg=${1:-"Proceed?"}
local REPLY
printf "%s" "$(_dc_yellow "$msg [y/N]: ")"
read -r -k 1 REPLY 2>/dev/null || read -r -n 1 REPLY
echo
[[ $REPLY =~ ^[Yy]$ ]]
}
# Get services by Dozzle group label
_dc_group() {
local group=$1
_dc_init || return 1
_dc_plain config 2>/dev/null | \
awk -v grp="$group" '
/^ [a-z].*:$/ { svc=$1; gsub(/:$/,"",svc) }
/dozzle\.group:/ && $2 == grp { print svc }
' | tr '\n' ' '
}
# Clear any conflicting aliases from oh-my-zsh docker-compose plugin
unalias dc dcdown dcup dcpull dcrestart dcps dclogs dcexec dcconfig dcstats dctop dcq 2>/dev/null
unalias dcrecreate dcrs dcprune dcdf dcinfo dcfiles dchelp 2>/dev/null
# Core wrapper
function dc {
_dc_init || return 1
_dc_compose "$@"
}
# Full Stack Commands
function dcdown {
_dc_init || return 1
if [[ "$1" != "-f" ]] && [[ "$1" != "--force" ]]; then
_dc_confirm "Stop ALL containers?" || { _dc_yellow "Cancelled"; return 0; }
else
shift
fi
_dc_blue "Stopping all services..."
_dc_compose down "$@"
_dc_green "All services stopped"
}
# shellcheck disable=SC2120
function dcpull {
_dc_init || return 1
local images
# Use _dc_plain (no op run) — pulling images doesn't need secrets
if [[ $# -eq 0 ]]; then
images=$(_dc_plain config --images 2>/dev/null | sort -u)
# Include images from standalone compose files (e.g. compose.*.yml)
local server_dir
server_dir=$(echo "$COMPOSE_FILE" | tr ':' '\n' | head -1 | xargs dirname)
if [[ -n "$server_dir" ]]; then
for f in "$server_dir"/compose.*.yml; do
[[ -f "$f" ]] || continue
[[ "$COMPOSE_FILE" == *"$(basename "$f")"* ]] && continue
local extra
extra=$(docker compose -f "$f" config --images 2>/dev/null)
[[ -n "$extra" ]] && images=$(printf '%s\n%s' "$images" "$extra" | sort -u)
done
fi
else
images=$(_dc_plain config --images "$@" 2>/dev/null | sort -u)
fi
local total
total=$(echo "$images" | wc -l)
local count=0 failed=0
while IFS= read -r img; do
[[ -z "$img" ]] && continue
((count++))
local short="${img##*/}"
_dc_blue "[$count/$total] Pulling ${short}..."
if ! docker pull --quiet "$img"; then
((failed++))
_dc_red "Failed to pull $img"
fi
done <<< "$images"
if (( failed > 0 )); then
_dc_yellow "Pull complete ($total images, $failed failed)"
else
_dc_green "Pull complete ($total unique images)"
fi
}
function dcup {
_dc_init || return 1
local services
if [[ $# -eq 0 ]]; then
services=$(_dc_compose config --services 2>/dev/null)
_dc_blue "Starting all services..."
_dc_compose up -d
else
services="$*"
local total
total=$(echo "$services" | wc -w)
local count=0
for svc in $services; do
((count++))
_dc_blue "[$count/$total] Starting $svc..."
_dc_compose up -d "$svc"
done
fi
_dc_green "Services started"
}
function dcrestart {
if [[ "$1" == "-f" ]] || [[ "$1" == "--force" ]]; then
shift
else
_dc_confirm "Full restart (down → pull → up)?" || { _dc_yellow "Cancelled"; return 0; }
fi
if [[ $# -gt 0 ]]; then
_dc_yellow "dcrestart operates on the full stack. Use 'dcrs <service>' for single-service restart."
return 1
fi
dcdown -f && dcpull && dcup
}
# Monitoring Commands
function dcps {
_dc_init || return 1
_dc_compose ps "$@"
}
function dclogs {
_dc_init || return 1
_dc_compose logs -f "$@"
}
function dcexec {
_dc_init || return 1
_dc_compose exec "$@"
}
function dcconfig {
_dc_init || return 1
_dc_compose config "$@"
}
function dcstats {
docker stats "$@"
}
function dctop {
_dc_init || return 1
_dc_compose top "$@"
}
# Quick status overview
function dcq {
_dc_init || return 1
local running stopped unhealthy
running=$(_dc_compose ps --status running -q 2>/dev/null | wc -l)
stopped=$(_dc_compose ps --status exited -q 2>/dev/null | wc -l)
unhealthy=$(docker ps --filter "health=unhealthy" -q 2>/dev/null | wc -l)
echo "Running: $(_dc_green "$running") | Stopped: $(_dc_yellow "$stopped") | Unhealthy: $(_dc_red "$unhealthy")"
}
# Dozzle Group Commands (dynamic from container labels)
function grpdown {
local grp=$1; shift
_dc_init || return 1
local services
services=$(_dc_group "$grp")
[[ -z "$services" ]] && { _dc_red "No services in group: $grp"; return 1; }
_dc_blue "Stopping $grp: $services"
_dc_compose stop $services "$@"
_dc_green "$grp stopped"
}
function grpup {
local grp=$1; shift
_dc_init || return 1
local services
services=$(_dc_group "$grp")
[[ -z "$services" ]] && { _dc_red "No services in group: $grp"; return 1; }
_dc_blue "Starting $grp: $services"
_dc_compose up -d $services "$@"
_dc_green "$grp started"
}
function grplogs {
local grp=$1; shift
_dc_init || return 1
local services
services=$(_dc_group "$grp")
[[ -z "$services" ]] && { _dc_red "No services in group: $grp"; return 1; }
_dc_compose logs -f $services "$@"
}
function grpps {
local grp=$1; shift
_dc_init || return 1
local services
services=$(_dc_group "$grp")
[[ -z "$services" ]] && { _dc_red "No services in group: $grp"; return 1; }
_dc_compose ps $services "$@"
}
function grprestart {
local grp=$1; shift
_dc_init || return 1
local services
services=$(_dc_group "$grp")
[[ -z "$services" ]] && { _dc_red "No services in group: $grp"; return 1; }
_dc_blue "Restarting $grp: $services"
_dc_compose restart $services "$@"
_dc_green "$grp restarted"
}
# List available Dozzle groups
function grplist {
_dc_init || return 1
_dc_blue "Available Dozzle groups:"
_dc_plain config 2>/dev/null | grep "dozzle\.group:" | awk '{print $2}' | sort -u
}
# Show services in a group
function grpshow {
local grp=$1
_dc_init || return 1
local services
services=$(_dc_group "$grp")
[[ -z "$services" ]] && { _dc_red "No services in group: $grp"; return 1; }
echo "$grp: $services"
}
# Utility Commands
function dcrecreate {
_dc_init || return 1
_dc_compose up -d --force-recreate "$@"
}
function dcrs {
_dc_init || return 1
_dc_compose restart "$@"
}
function dcprune {
docker system prune "$@"
}
function dcdf {
docker system df "$@"
}
function dcinfo {
_dc_init || return 1
echo "Docker Compose Configuration"
echo "============================="
echo "Directory: $DOCKER_GIT_DIR"
echo "Compose files: ${COMPOSE_FILE//:/ }"
echo ""
echo "Service count: $(_dc_plain config --services 2>/dev/null | wc -l)"
echo ""
dcq
}
function dcfiles {
_dc_init || return 1
echo "Compose files in use:"
echo "${COMPOSE_FILE//:/$'\n'}"
}
function dchelp {
cat << 'EOF'
Docker Compose Aliases Quick Reference
======================================
Full Stack:
dc [cmd] docker compose (with op run for secrets)
dcdown [-f] docker compose down (confirm unless -f)
dcpull docker pull (unique images, quiet, progress)
dcup docker compose up -d
dcrestart [-f] dcdown → dcpull → dcup
Monitoring:
dcps docker compose ps
dcq Quick status (running/stopped/unhealthy counts)
dclogs [svc] docker compose logs -f
dcexec svc cmd docker compose exec
dcconfig docker compose config
dcstats docker stats
dctop docker compose top
Dozzle Groups (dynamic from labels):
grplist List all Dozzle groups
grpshow <group> Show services in a group
grp[up|down|logs|ps|restart] <group> Generic group commands
Utility:
dcrecreate svc docker compose up -d --force-recreate
dcrs svc docker compose restart
dcprune docker system prune
dcdf docker system df
dcinfo Show config state + quick status
dcfiles List compose files in use
Interactive (requires fzf):
dclogsi Pick service to tail logs
dcexeci Pick service to exec into
dcrsi Pick service(s) to restart
dcrecreatei Pick service(s) to recreate
dcupi Pick service(s) to start
dcdowni Pick service(s) to stop
dcpsi Browse containers with log preview
grpi Pick group and show services
grp[up|down|logs|ps]i Pick group interactively
EOF
}
# Shell-specific completion
if [[ -n "$BASH_VERSION" ]]; then
_dc_services() {
local cur="${COMP_WORDS[COMP_CWORD]}"
local services
if [[ -z "$COMPOSE_FILE" ]] && [[ -f "$DOCKER_GIT_DIR/.env" ]]; then
COMPOSE_FILE=$(grep '^COMPOSE_FILE=' "$DOCKER_GIT_DIR/.env" 2>/dev/null | cut -d= -f2-)
export COMPOSE_FILE
fi
mapfile -t services < <(_dc_plain config --services 2>/dev/null)
mapfile -t COMPREPLY < <(compgen -W "${services[*]}" -- "$cur")
}
complete -F _dc_services dclogs dcexec dcrecreate dcrs dc
elif [[ -n "$ZSH_VERSION" ]]; then
_dc_services() {
local services
if [[ -z "$COMPOSE_FILE" ]] && [[ -f "$DOCKER_GIT_DIR/.env" ]]; then
COMPOSE_FILE=$(grep '^COMPOSE_FILE=' "$DOCKER_GIT_DIR/.env" 2>/dev/null | cut -d= -f2-)
export COMPOSE_FILE
fi
# shellcheck disable=SC2296,SC2206
services=(${(f)"$(_dc_plain config --services 2>/dev/null)"})
_describe 'service' services
}
compdef _dc_services dclogs dcexec dcrecreate dcrs dc 2>/dev/null || true
fi
# FZF Integration (if available)
if command -v fzf &>/dev/null; then
_dc_fzf_pick() {
local multi=${1:-false}
_dc_init || return 1
local opts=""
[[ "$multi" == "true" ]] && opts="-m"
_dc_plain config --services 2>/dev/null | fzf $opts --height 40% --reverse --border --header "Select service(s)"
}
_dc_fzf_group() {
_dc_init || return 1
_dc_plain config 2>/dev/null | grep "dozzle\.group:" | awk '{print $2}' | sort -u | \
fzf --height 40% --reverse --border --header "Select group"
}
function grpi { local grp; grp=$(_dc_fzf_group); [[ -n "$grp" ]] && grpshow "$grp"; }
function grpupi { local grp; grp=$(_dc_fzf_group); [[ -n "$grp" ]] && grpup "$grp"; }
function grpdowni { local grp; grp=$(_dc_fzf_group); [[ -n "$grp" ]] && grpdown "$grp"; }
function grplogsi { local grp; grp=$(_dc_fzf_group); [[ -n "$grp" ]] && grplogs "$grp"; }
function grppsi { local grp; grp=$(_dc_fzf_group); [[ -n "$grp" ]] && grpps "$grp"; }
function dclogsi { local svc; svc=$(_dc_fzf_pick); [[ -n "$svc" ]] && dclogs "$svc"; }
function dcexeci { local svc; svc=$(_dc_fzf_pick); [[ -n "$svc" ]] && dcexec "$svc" "${@:-bash}"; }
function dcrsi {
local svc; svc=$(_dc_fzf_pick true)
[[ -n "$svc" ]] && while IFS= read -r s; do dcrs "$s"; done <<< "$svc"
}
function dcrecreatei {
local svc; svc=$(_dc_fzf_pick true)
[[ -n "$svc" ]] && while IFS= read -r s; do dcrecreate "$s"; done <<< "$svc"
}
function dcupi {
local svc; svc=$(_dc_fzf_pick true)
[[ -n "$svc" ]] && while IFS= read -r s; do dcup "$s"; done <<< "$svc"
}
function dcdowni {
local svc; svc=$(_dc_fzf_pick true)
[[ -n "$svc" ]] && { _dc_init || return 1; while IFS= read -r s; do _dc_compose stop "$s"; done <<< "$svc"; }
}
function dcpsi {
_dc_init || return 1
_dc_plain ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" | \
fzf --header-lines=1 --height 60% --reverse --border \
--preview 'docker logs --tail 20 {1}' \
--preview-window=down:40%:wrap
}
fi