-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstart.sh
More file actions
executable file
Β·399 lines (337 loc) Β· 14 KB
/
Copy pathstart.sh
File metadata and controls
executable file
Β·399 lines (337 loc) Β· 14 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
#!/bin/bash
set -x # echo on
set -euo pipefail
# Directory of this script
SCRIPT_DIR="$(dirname "$0")"
ARCHITECTURE=$(uname -m)
NUM_CORES=$(nproc)
MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
PERSISTENT_DIR="/var/lib/app"
PLANET_FILE="$PERSISTENT_DIR/planet-latest.osm.pbf"
PLANET_URL="https://planet.openstreetmap.org/pbf/planet-latest.osm.pbf"
# to load an extract, replace the above URL with something like "https://download.geofabrik.de/north-america/us/rhode-island-latest.osm.pbf"
PG_VERSION="18"
POSTGIS_MAJOR_VERSION="3"
PG_CONF_PATH="/etc/postgresql/${PG_VERSION}/main/postgresql.conf"
PG_DATA_DIR="$PERSISTENT_DIR/pg_data"
DB_NAME="osm"
DB_USER="osmuser"
DB_TABLE_PREFIX="planet_osm"
OSM2PGSQL_VERSION="2.2.0"
OSM2PGSQL_DIR="/usr/local/osm2pgsql"
OSM2PGSQL_BUILD_DIR="/usr/local/src/osm2pgsql"
FLAT_NODES_FILE="$PERSISTENT_DIR/flatnodes"
LUA_STYLE_FILE="$SCRIPT_DIR/config/osm2pgsql_style_config.lua"
MARTIN_VERSION="0.19.3"
MARTIN_CONFIG_FILE="$SCRIPT_DIR/config/martin_config.yaml"
MARTIN_WORKERS=6
MARTIN_POOL_SIZE=6
VARNISH_VERSION="8.0.0"
VARNISH_DIR="/usr/local/varnish"
VARNISH_BUILD_DIR="/usr/local/src/varnish"
VARNISH_ETC_DIR="/usr/local/varnish/etc"
VARNISH_CONFIG_FILE="$SCRIPT_DIR/config/varnish_config.vcl"
VARNISH_CACHE_RAM_GB="6"
VARNISH_WORKING_DIR="/var/lib/varnish/martin"
[[ "$ARCHITECTURE" == "x86_64" || "$ARCHITECTURE" == "aarch64" ]] && echo "Architecture: $ARCHITECTURE" || { echo "Unsupported architecture: $ARCHITECTURE"; exit 1; }
# Create linux user matching PG role: needed for pgsql peer authentication
if id "$DB_USER" &>/dev/null; then
echo "User '$DB_USER' already exists."
else
echo "Creating user '$DB_USER'..."
sudo useradd -m "$DB_USER"
echo "User '$DB_USER' created."
fi
# Create helper directory
if [ ! -d "$PERSISTENT_DIR" ]; then
mkdir -p "$PERSISTENT_DIR"
fi
# Make our user the owner of the helper directory
if [ "$(stat -c %U "$PERSISTENT_DIR")" != "$DB_USER" ]; then
sudo chown "$DB_USER":"$DB_USER" "$PERSISTENT_DIR"
fi
# We need to install all of our prerequisite commands here instead of in the Docker image since
# we may not always deploy via the Docker image
# Install wget: needed to fetch planetfile
if ! command -v wget >/dev/null 2>&1; then
echo "wget not found, installing..."
sudo apt update && sudo apt install -y wget
command -v wget &> /dev/null && echo "wget successfully installed." || { echo "Failed to install wget."; exit 1; }
fi
# Install git: needed to clone repos
if ! command -v git >/dev/null 2>&1; then
echo "git not found, installing..."
sudo apt update && sudo apt install -y git
command -v git &> /dev/null && echo "git successfully installed." || { echo "Failed to install git."; exit 1; }
fi
# Install Martin: the tileserver
if ! command -v martin >/dev/null 2>&1; then
echo "Martin not found. Downloading binary..."
MARTIN_BINARY_NAME="martin-${ARCHITECTURE}-unknown-linux-gnu"
wget -O "${MARTIN_BINARY_NAME}.tar.gz" "https://github.com/maplibre/martin/releases/download/martin-v${MARTIN_VERSION}/${MARTIN_BINARY_NAME}.tar.gz" || { echo "Download failed"; exit 1; }
mkdir "${MARTIN_BINARY_NAME}"
tar -xvzf "${MARTIN_BINARY_NAME}.tar.gz" -C "${MARTIN_BINARY_NAME}" || { echo "Extraction failed"; exit 1; }
sudo mv -f "${MARTIN_BINARY_NAME}/martin" /usr/local/bin/ || { echo "Move failed"; exit 1; }
rm -rf "${MARTIN_BINARY_NAME}.tar.gz" "${MARTIN_BINARY_NAME}"
martin --version
else
echo "Martin is already installed: $(martin --version)"
fi
# Install Varnish: the tile cache
if ! command -v "$VARNISH_DIR/sbin/varnishd" >/dev/null 2>&1; then
# We need to build osm2pgsql from source since the bundled version is too old
echo "Cloning and building Varnish $VARNISH_VERSION..."
echo "Installing dependencies..."
sudo apt update
sudo apt install -y \
make \
automake \
autotools-dev \
libedit-dev \
libjemalloc-dev \
libncurses-dev \
libpcre2-dev \
libtool \
pkg-config \
python3-docutils \
python3-sphinx \
cpio
mkdir -p "$VARNISH_BUILD_DIR"
cd "$VARNISH_BUILD_DIR"
wget "https://vinyl-cache.org/downloads/varnish-$VARNISH_VERSION.tgz"
tar xzf "varnish-$VARNISH_VERSION.tgz"
cd "varnish-$VARNISH_VERSION"
./configure --prefix="$VARNISH_DIR"
make -j$(nproc)
sudo make install
# return to script dir and clean up
cd "$SCRIPT_DIR"
rm -rf "$VARNISH_BUILD_DIR"
"$VARNISH_DIR/sbin/varnishd" -V
echo "Varnish $VARNISH_VERSION installed at $VARNISH_DIR"
fi
# Install osm2pgsql
if ! command -v "$OSM2PGSQL_DIR/bin/osm2pgsql" >/dev/null 2>&1; then
# We need to build osm2pgsql from source since the bundled version is too old
echo "Cloning and building osm2pgsql $OSM2PGSQL_VERSION..."
echo "Installing dependencies..."
sudo apt update
sudo apt install -y \
make cmake g++ libboost-dev \
libexpat1-dev zlib1g-dev libpotrace-dev \
libopencv-dev libbz2-dev libpq-dev libproj-dev lua5.3 liblua5.3-dev \
pandoc nlohmann-json3-dev \
pyosmium python3-psycopg
# pyosmium and python3-psycopg are required for osm2pgsql-replication even if we didn't have to build osm2pgsql from source
mkdir "$OSM2PGSQL_BUILD_DIR"
cd "$OSM2PGSQL_BUILD_DIR"
git clone https://github.com/openstreetmap/osm2pgsql.git .
git fetch --tags
git checkout "tags/$OSM2PGSQL_VERSION" -b "build-$OSM2PGSQL_VERSION"
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="$OSM2PGSQL_DIR" ..
make -j$(nproc)
make install
# return to script dir and clean up
cd "$SCRIPT_DIR"
rm -rf "$OSM2PGSQL_BUILD_DIR"
"$OSM2PGSQL_DIR/bin/osm2pgsql" --version
echo "osm2pgsql $OSM2PGSQL_VERSION installed at $OSM2PGSQL_DIR"
fi
# Install PostgreSQL
if command -v psql > /dev/null; then
echo "PostgreSQL is already installed: $(psql -V)"
else
echo "PostgreSQL is not installed. Proceeding with installation..."
# delete any possible stale postgres data
rm -rf "$PG_DATA_DIR"
sudo apt update
sudo apt install -y postgresql-common
# Add PGDG repo
if ! grep -q apt.postgresql.org /etc/apt/sources.list /etc/apt/sources.list.d/*; then
echo "Adding PostgreSQL APT repo..."
sudo apt install -y wget gnupg lsb-release
wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
fi
# Explicitly install only the version we want
sudo apt install -y \
postgresql-$PG_VERSION \
postgresql-contrib-$PG_VERSION \
postgresql-$PG_VERSION-postgis-$POSTGIS_MAJOR_VERSION \
postgresql-$PG_VERSION-postgis-$POSTGIS_MAJOR_VERSION-scripts
fi
# Ensure dir exists
if [ ! -d "$PG_DATA_DIR" ]; then
mkdir -p "$PG_DATA_DIR"
fi
if [ "$(stat -c %U "$PG_DATA_DIR")" != "postgres" ]; then
sudo chown postgres:postgres "$PG_DATA_DIR"
fi
if [ ! -f "$PG_DATA_DIR/PG_VERSION" ]; then
echo "Initializing new PostgreSQL cluster at $PG_DATA_DIR"
sudo -u postgres "/usr/lib/postgresql/${PG_VERSION}/bin/initdb" -D "$PG_DATA_DIR"
fi
# Ensure the config file exists
if [ ! -f "$PG_CONF_PATH" ]; then
echo "postgresql.conf not found at $PG_CONF_PATH"
exit 1
fi
if ! grep -q "^#\?data_directory = '$PG_DATA_DIR'" "$PG_CONF_PATH"; then
# Set the postgres data storage directory
sudo sed -i "s|^#\?data_directory =.*|data_directory = '$PG_DATA_DIR'|" "$PG_CONF_PATH"
echo "data_directory updated to $PG_DATA_DIR"
fi
# Start PostgreSQL
if pg_isready > /dev/null 2>&1 && pgrep -x "postgres" > /dev/null; then
sudo service postgresql restart
else
sudo service postgresql start
fi
until pg_isready > /dev/null 2>&1; do sleep 1; done
if sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname = '$DB_USER'" | grep -q 1; then
echo "User '$DB_USER' exists."
else
echo "Creating user '$DB_USER'..."
sudo -u postgres createuser "$DB_USER"
sudo -u postgres psql --command='ALTER ROLE osmuser SET plan_cache_mode = force_custom_plan;'
fi
# Setup database
if sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname = '$DB_NAME'" | grep -q 1; then
echo "Database '$DB_NAME' exists."
else
echo "Creating database '$DB_NAME'..."
sudo -u postgres createdb --encoding=UTF8 --owner="$DB_USER" "$DB_NAME"
sudo -u postgres psql "$DB_NAME" --command='CREATE EXTENSION postgis;'
sudo -u postgres psql "$DB_NAME" --command='CREATE EXTENSION hstore;'
fi
# Load data into database
TABLES_EXISTING=$(sudo -u postgres psql -d "$DB_NAME" -tAc \
"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_name LIKE '${DB_TABLE_PREFIX}_%';")
if [[ "$TABLES_EXISTING" -gt 0 ]]; then
echo "osm2pgsql import detected β $TABLES_EXISTING tables found with prefix '${DB_TABLE_PREFIX}_'."
else
# Set import params dynamically based on available memory
SHARED_BUFFERS_MB=$(( MEM_KB * 25 / 100 / 1024 )) # 25% RAM
MAINTENANCE_MB=$(( MEM_KB * 60 / 100 / 1024 )) # 60% RAM
AUTOVAC_MB=$(( MEM_KB * 25 / 100 / 1024 )) # 25% RAM
EFFECTIVE_CACHE_MB=$(( MEM_KB * 75 / 100 / 1024 )) # 75% RAM
AVAILABLE_BYTES=$(df --output=avail -B1 "$PG_DATA_DIR" | tail -n1)
AVAILABLE_TB=$((AVAILABLE_BYTES / 1024 / 1024 / 1024 / 1024))
if [ "$AVAILABLE_TB" -ge 1 ]; then
MIN_WAL_SIZE_GB=32
MAX_WAL_SIZE_GB=128
elif [ "$AVAILABLE_TB" -ge 0.5 ]; then
MIN_WAL_SIZE_GB=4
MAX_WAL_SIZE_GB=16
else
MIN_WAL_SIZE_GB=1
MAX_WAL_SIZE_GB=4
fi
declare -A PARAMS=(
["shared_buffers"]="${SHARED_BUFFERS_MB}MB"
["work_mem"]="64MB"
["maintenance_work_mem"]="${MAINTENANCE_MB}MB"
["autovacuum_work_mem"]="${AUTOVAC_MB}MB"
["effective_cache_size"]="${EFFECTIVE_CACHE_MB}MB"
["wal_level"]="minimal"
["synchronous_commit"]="off"
["full_page_writes"]="off"
["checkpoint_timeout"]="60min"
["min_wal_size"]="${MIN_WAL_SIZE_GB}GB"
["max_wal_size"]="${MAX_WAL_SIZE_GB}GB"
["checkpoint_completion_target"]="0.9"
["max_connections"]="100"
["max_worker_processes"]="12"
["max_parallel_workers"]="6"
["max_parallel_workers_per_gather"]="3"
["max_wal_senders"]="0"
["random_page_cost"]="1.0"
["effective_io_concurrency"]="8"
["temp_buffers"]="64MB"
["autovacuum"]="off"
["jit"]="off"
)
for key in "${!PARAMS[@]}"; do
value="${PARAMS[$key]}"
# Check if value is already as desired
if grep -Eq "^[[:space:]]*${key}[[:space:]]*=[[:space:]]*${value}\b" "$PG_CONF_PATH"; then
continue
fi
# Remove any existing lines for this parameter (commented or active)
sudo sed -i "/^[[:space:]]*#\?[[:space:]]*${key}[[:space:]]*=/d" "$PG_CONF_PATH"
# Append desired parameter
echo "${key} = ${value}" | sudo tee -a "$PG_CONF_PATH" >/dev/null
done
# Restart postgres so our config file changes take effect
sudo service postgresql restart
until pg_isready > /dev/null 2>&1; do sleep 1; done
# Remove stale flat nodes cache file, if any
rm -f -- "$FLAT_NODES_FILE"
echo "Downloading the OSM Planet file..."
if [ ! -f "$PLANET_FILE" ]; then
wget "$PLANET_URL" -O "$PLANET_FILE"
else
echo "Planet file already exists: $PLANET_FILE"
fi
# Allow 2 GB of RAM for node cache if not using flat nodes file
NODE_CACHE_PARAMS="--cache=2000"
# Cache nodes in a flat file if input is larger than 10 GB, per https://osm2pgsql.org/doc/manual.html#flat-node-store
if [[ -f "$PLANET_FILE" ]] && [[ $(stat -c%s "$PLANET_FILE") -gt 10737418240 ]]; then
NODE_CACHE_PARAMS="--flat-nodes=$FLAT_NODES_FILE --cache=0"
fi
echo "Running import..."
# These options are documented but are not needed with flex output: --merc --multi-geometry --keep-coastlines
sudo -u "$DB_USER" "$OSM2PGSQL_DIR/bin/osm2pgsql" \
-d "$DB_NAME" \
-U "$DB_USER" \
--create \
--slim \
--extra-attributes \
$NODE_CACHE_PARAMS \
--prefix="$DB_TABLE_PREFIX" \
--output=flex \
--style="$LUA_STYLE_FILE" \
"$PLANET_FILE"
echo "Running post-import SQL queries..."
sudo -u "$DB_USER" psql "$DB_NAME" --file="$SCRIPT_DIR/sql/post_init_or_update/area_relation.sql"
# We need to manually do this since we turned off autovacuum for the import
echo "Running manual SQL vacuum..."
sudo -u "$DB_USER" psql "$DB_NAME" --command="VACUUM;"
# We need to do this once in order to run `update` later, but it's safe to repeat
echo "Running osm2pgsql-replication init..."
sudo -u "$DB_USER" "$OSM2PGSQL_DIR/bin/osm2pgsql-replication" init \
-d "$DB_NAME" \
-U "$DB_USER"
fi
bash "$SCRIPT_DIR/update_postgres_config.sh"
# Reinstall functions every time in case something changed.
# In order to pass validation, we have to do this after the database has been populated
bash "$SCRIPT_DIR/update_sql_functions.sh"
if [ ! -d "$VARNISH_WORKING_DIR" ]; then
mkdir -p "$VARNISH_WORKING_DIR"
fi
if [ ! -d "$VARNISH_ETC_DIR" ]; then
mkdir -p "$VARNISH_ETC_DIR"
sudo head -c 32 /dev/urandom | base64 | sudo tee "$VARNISH_ETC_DIR/secret"
sudo groupadd varnishadmin
sudo usermod -aG varnishadmin "$DB_USER"
sudo chgrp varnishadmin "$VARNISH_ETC_DIR/secret"
sudo chmod 640 "$VARNISH_ETC_DIR/secret"
fi
# start Varnish
if ! pgrep -x varnishd >/dev/null 2>&1; then
echo "Starting Varnish..."
sudo "$VARNISH_DIR/sbin/varnishd" \
-n "$VARNISH_WORKING_DIR" \
-T 127.0.0.1:6082 \
-S "$VARNISH_ETC_DIR/secret" \
-a :6081 \
-f "$VARNISH_CONFIG_FILE" \
-s "malloc,${VARNISH_CACHE_RAM_GB}G"
echo "Varnish started."
fi
# start Martin
sudo -u "$DB_USER" -- /usr/local/bin/martin --config "$MARTIN_CONFIG_FILE" --workers "$MARTIN_WORKERS" --pool-size "$MARTIN_POOL_SIZE"