-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·308 lines (265 loc) · 9.33 KB
/
install.sh
File metadata and controls
executable file
·308 lines (265 loc) · 9.33 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
#!/bin/bash
set -e
# Check Docker
if ! docker version &> /dev/null; then
echo "Please install Docker"
exit 1
fi
# Get Docker version
DOCKER_VERSION=$(docker version --format '{{.Server.Version}}' 2>/dev/null || docker version | grep -E 'Version:' | head -n1 | awk '{print $2}')
# Function to compare versions
version_lt() {
# Returns 0 if $1 < $2, 1 otherwise
# Handles versions like 20.10.9, 19.03.13, etc.
local v1=$1
local v2=$2
# Convert to comparable format (e.g., 20.10.9 -> 200109)
local v1_comparable=$(echo "$v1" | awk -F. '{printf "%d%02d%02d", $1, $2, $3}')
local v2_comparable=$(echo "$v2" | awk -F. '{printf "%d%02d%02d", $1, $2, $3}')
if [ "$v1_comparable" -lt "$v2_comparable" ]; then
return 0
else
return 1
fi
}
# Check if Docker version is less than 20.10.10
USE_SECCOMP=false
if version_lt "$DOCKER_VERSION" "20.10.10"; then
USE_SECCOMP=true
echo "Detected Docker version $DOCKER_VERSION (< 20.10.10), will use seccomp profile"
else
echo "Detected Docker version $DOCKER_VERSION (>= 20.10.10)"
fi
# Check Docker Compose
if docker compose version &> /dev/null; then
COMPOSE_CMD="docker compose"
COMPOSE_VERSION=$(docker compose version --short 2>/dev/null || docker compose version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
elif docker-compose version &> /dev/null; then
COMPOSE_CMD="docker-compose"
COMPOSE_VERSION=$(docker-compose version --short 2>/dev/null || docker-compose version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
else
echo "Please install Docker Compose"
exit 1
fi
# Check Docker Compose version is >= 1.25.0
MIN_COMPOSE_VERSION="1.25.0"
if version_lt "$COMPOSE_VERSION" "$MIN_COMPOSE_VERSION"; then
echo "Error: Docker Compose version $COMPOSE_VERSION is too old. Minimum required version is $MIN_COMPOSE_VERSION"
echo "Please upgrade Docker Compose: https://docs.docker.com/compose/install/"
exit 1
fi
echo "Detected Docker Compose version $COMPOSE_VERSION (>= $MIN_COMPOSE_VERSION)"
# Check COLLECTOR_SECRET
if [ -z "$COLLECTOR_SECRET" ]; then
echo "Please set COLLECTOR_SECRET environment variable"
exit 1
fi
# Optional proxy port and TLS indicator
PROXY_PORT="${PROXY_PORT:-}"
USE_TLS="${USE_TLS:-}"
# Optional custom host mount paths (comma-separated)
MOUNT_HOST_PATHS="${MOUNT_HOST_PATHS:-}"
# Validate PROXY_PORT if set
if [ -n "$PROXY_PORT" ]; then
if ! [[ "$PROXY_PORT" =~ ^[0-9]+$ ]]; then
echo "Error: PROXY_PORT must be an integer."
exit 1
fi
# Check for conflicts with internal ports
if [ "$PROXY_PORT" -eq 33000 ] || [ "$PROXY_PORT" -eq 34320 ] || [ "$PROXY_PORT" -eq 39090 ]; then
echo "Error: PROXY_PORT cannot be 33000, 34320, or 39090 as these are internal collector ports."
exit 1
fi
# If USE_TLS is set and PROXY_PORT is 80, that's a conflict
if [ -n "$USE_TLS" ] && [ "$PROXY_PORT" -eq 80 ]; then
echo "Error: PROXY_PORT cannot be 80 when USE_TLS is set (port 80 is reserved for ACME HTTP-01)."
exit 1
fi
fi
# Set hostname if not provided
HOSTNAME="${HOSTNAME:-$(hostname)}"
# Set default values for environment variables
BASE_URL="${BASE_URL:-https://telemetry.betterstack.com}"
CLUSTER_COLLECTOR="${CLUSTER_COLLECTOR:-false}"
ENABLE_DOCKERPROBE="${ENABLE_DOCKERPROBE:-true}"
# Create temporary directory and cd into it
TEMP_DIR=$(mktemp -d)
cd "$TEMP_DIR"
# Clean up on exit
trap "rm -rf $TEMP_DIR" EXIT
# Download appropriate compose file based on Docker version
if [ "$USE_SECCOMP" = true ]; then
# For older Docker versions, use the seccomp-enabled compose file
curl -sSL https://raw.githubusercontent.com/BetterStackHQ/collector/main/docker-compose.seccomp.yml \
-o docker-compose.yml
# Also download the seccomp profile
curl -sSL https://raw.githubusercontent.com/BetterStackHQ/collector/main/collector-seccomp.json \
-o collector-seccomp.json
else
# For newer Docker versions, use the standard compose file
curl -sSL https://raw.githubusercontent.com/BetterStackHQ/collector/main/docker-compose.yml \
-o docker-compose.yml
fi
# Adjust Compose port exposure rules
# - Adds ports section to collector service (inserted before volumes section)
# - If PROXY_PORT present, add host mapping: ${PROXY_PORT}:${PROXY_PORT} (for upstream proxy in Vector)
# - Add port 80 for ACME validation when PROXY_PORT==443 or USE_TLS is set (and PROXY_PORT!=80)
adjust_compose_ports() {
local file="$1"
local tmpfile
tmpfile="$(mktemp)"
# Determine if we should bind port 80
local bind80=""
if [ "$PROXY_PORT" = "443" ] || ([ -n "$USE_TLS" ] && [ "$PROXY_PORT" != "80" ]); then
bind80="yes"
fi
awk -v addport="$PROXY_PORT" -v add80="$bind80" '
BEGIN { inserted=0; in_collector=0 }
{
# Remove previously inserted install lines for idempotence
if ($0 ~ /# install: (proxy port|acme http-01|ports section)/) { next }
if ($0 ~ /^[[:space:]]*ports:[[:space:]]*$/ && in_collector==1) { next }
# Track if we are in the collector service
if ($0 ~ /^[[:space:]]*collector:[[:space:]]*$/) {
in_collector=1
}
# Reset when we hit the next service (beyla, etc.)
if ($0 ~ /^[[:space:]]*[a-z_-]+:[[:space:]]*$/ && $0 !~ /collector:/) {
in_collector=0
}
# Insert ports section before volumes section in collector
if (in_collector==1 && inserted==0 && $0 ~ /^[[:space:]]*volumes:[[:space:]]*$/) {
if (addport != "" || add80 != "") {
print " ports: # install: ports section"
if (addport != "") {
print " - \"" addport ":" addport "\" # install: proxy port"
}
if (add80 != "") {
print " - \"80:80\" # install: acme http-01"
}
}
inserted=1
}
print $0
}
' "$file" > "$tmpfile"
mv "$tmpfile" "$file"
}
adjust_image_tag() {
local file="$1"
local tag="$2"
local tmpfile
tmpfile="$(mktemp)"
sed "s/:latest/:${tag}/g" "$file" > "$tmpfile"
mv "$tmpfile" "$file"
}
# Adjust volume mounts based on MOUNT_HOST_PATHS environment variable
# If MOUNT_HOST_PATHS is set, replace the default /:/host:ro mount with specific paths
adjust_compose_volumes() {
local file="$1"
local tmpfile
tmpfile="$(mktemp)"
local mount_tmpfile
mount_tmpfile="$(mktemp)"
if [ -n "$MOUNT_HOST_PATHS" ]; then
# Parse comma-separated paths and write to temporary file
IFS=',' read -ra PATHS <<< "$MOUNT_HOST_PATHS"
for path in "${PATHS[@]}"; do
# Trim whitespace
path=$(echo "$path" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
# Skip empty paths
if [ -n "$path" ]; then
# Remove trailing slash if present
path="${path%/}"
echo " - ${path}:/host${path}:ro" >> "$mount_tmpfile"
fi
done
# Replace the /:/host:ro line with custom mount lines from file
awk -v mounts_file="$mount_tmpfile" '
{
# Replace the /:/host:ro mount with custom paths
if ($0 ~ /^[[:space:]]*- \/:\/host:ro[[:space:]]*$/) {
while ((getline line < mounts_file) > 0) {
print line
}
close(mounts_file)
} else {
print $0
}
}
' "$file" > "$tmpfile"
mv "$tmpfile" "$file"
rm -f "$mount_tmpfile"
fi
}
docker_v1_compatibility() {
local file="$1"
local tmpfile cleaned
tmpfile="$(mktemp)"
cleaned="$(mktemp)"
awk '
BEGIN { in_build = 0; build_indent = 0 }
/^[[:space:]]*#/ { next }
{
if ($0 ~ /^[[:space:]]*build:[[:space:]]*$/) {
match($0, /^[[:space:]]*/)
build_indent = RLENGTH
in_build = 1
next
}
if (in_build) {
match($0, /^[[:space:]]*/)
current_indent = RLENGTH
if (current_indent > build_indent) {
next
} else {
in_build = 0
}
}
sub(/ #[[:space:]].*$/, "")
sub(/[[:space:]]+$/, "")
print
}
' "$file" > "$cleaned"
if [ "$(sed -n '1p' "$cleaned")" != 'version: "2.4"' ]; then
{
echo 'version: "2.4"'
cat "$cleaned"
} > "$tmpfile"
else
cat "$cleaned" > "$tmpfile"
fi
mv "$tmpfile" "$file"
rm -f "$cleaned"
}
adjust_compose_ports docker-compose.yml
adjust_compose_volumes docker-compose.yml
# Replace :latest tag if IMAGE_TAG is set
if [ -n "$IMAGE_TAG" ]; then
echo "Replacing :latest with :$IMAGE_TAG in compose file"
adjust_image_tag docker-compose.yml "$IMAGE_TAG"
fi
if [ "$COMPOSE_CMD" = "docker-compose" ]; then
docker_v1_compatibility docker-compose.yml
fi
# Pull images first
COLLECTOR_SECRET="$COLLECTOR_SECRET" \
BASE_URL="$BASE_URL" \
CLUSTER_COLLECTOR="$CLUSTER_COLLECTOR" \
ENABLE_DOCKERPROBE="$ENABLE_DOCKERPROBE" \
HOSTNAME="$HOSTNAME" \
PROXY_PORT="$PROXY_PORT" \
$COMPOSE_CMD -p better-stack-collector pull
if [ "$COMPOSE_CMD" = "docker-compose" ]; then
# On docker-compose v1, try to stop and remove the container first with a 90s grace period
# This is a workaround for a bug in docker-compose v1 where the container stop grace period is not respected
$COMPOSE_CMD -p better-stack-collector stop -t 90 || true
fi
# Run containers
COLLECTOR_SECRET="$COLLECTOR_SECRET" \
BASE_URL="$BASE_URL" \
CLUSTER_COLLECTOR="$CLUSTER_COLLECTOR" \
ENABLE_DOCKERPROBE="$ENABLE_DOCKERPROBE" \
HOSTNAME="$HOSTNAME" \
PROXY_PORT="$PROXY_PORT" \
$COMPOSE_CMD -p better-stack-collector up -d --no-build