Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[+] add TimescaleDB metric storage based docker image, resolves #176 #183

Merged
merged 1 commit into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build-docker-timescale.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
docker build \
--build-arg GIT_TIME=`git show -s --format=%cI HEAD` \
--build-arg GIT_HASH=`git show -s --format=%H HEAD` \
-t cybertec/pgwatch3-timescale:latest \
-f docker/Dockerfile-timescale .
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Build web UI
FROM node:19 AS uibuilder
ADD src/webui /webui
RUN cd webui && yarn install && yarn build
RUN cd webui && yarn install --network-timeout 100000 && yarn build

# Build gatherer
FROM golang:1.20 as builder
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile-daemon
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Build web UI
FROM node:19 AS uibuilder
ADD src/webui /webui
RUN cd webui && yarn install && yarn build
RUN cd webui && yarn install --network-timeout 100000 && yarn build

FROM golang:alpine AS builder

Expand Down
88 changes: 88 additions & 0 deletions docker/Dockerfile-timescale
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Build web UI
FROM node:19 AS uibuilder
ADD src/webui /webui
RUN cd webui && yarn install --network-timeout 100000 && yarn build

# Build gatherer
FROM golang:1.20 as builder
ARG GIT_HASH
ARG GIT_TIME
ENV GIT_HASH=${GIT_HASH}
ENV GIT_TIME=${GIT_TIME}

ADD src /pgwatch3
COPY --from=uibuilder /webui/build /pgwatch3/webui/build
RUN cd /pgwatch3 && bash build_gatherer.sh

# Build the final image
FROM ubuntu:22.04

RUN apt-get -q update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -qy curl wget apt-transport-https vim git postgresql-common gnupg2 python3-pip \
&& sh /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y \
&& DEBIAN_FRONTEND=noninteractive apt-get install -qy postgresql-15 postgresql-plpython3-15 python3-psutil \
&& echo "deb https://packagecloud.io/timescale/timescaledb/ubuntu/ jammy main" | tee /etc/apt/sources.list.d/timescaledb.list \
&& wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | apt-key add - \
&& apt update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -qy timescaledb-2-postgresql-15 postgresql-15-pg-qualstats \
&& echo "include = 'pgwatch_postgresql.conf'" >> /etc/postgresql/15/main/postgresql.conf

RUN arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \
&& DEBIAN_FRONTEND=noninteractive apt-get install -qy libfontconfig1 \
&& wget -q -O grafana.deb "https://dl.grafana.com/oss/release/grafana_8.5.20_${arch}.deb" \
&& dpkg -i grafana.deb && rm grafana.deb


# Add pgwatch3 sources
ADD src /pgwatch3
# Copy over the compiled gatherer
COPY --from=builder /pgwatch3/pgwatch3 /pgwatch3

# For showing Git versions via :8080/versions or 'pgwatch3 --version'
ARG GIT_HASH
ARG GIT_TIME
ENV GIT_HASH=${GIT_HASH}
ENV GIT_TIME=${GIT_TIME}
RUN echo "${GIT_HASH} ${GIT_TIME}" > /pgwatch3/build_git_version.txt


# Grafana config customizations, Python requirements
RUN cp /pgwatch3/bootstrap/grafana_custom_config.ini /etc/grafana/grafana.ini \
&& pip3 install psutil supervisor pyyaml && mkdir /var/log/supervisor

ADD grafana_dashboards /pgwatch3/grafana_dashboards


# Set up supervisord [https://docs.docker.com/engine/admin/using_supervisord/]
COPY docker/supervisord-timescale.conf /etc/supervisor/supervisord.conf

# NB! When security is a concern one should definitely alter "pgwatch3" password in change_pw.sql and maybe modify pg_hba.conf accordingly
COPY docker/postgresql_timescale.conf /etc/postgresql/15/main/pgwatch_postgresql.conf
COPY docker/pg_hba.conf /etc/postgresql/15/main/pg_hba.conf
COPY docker/docker-launcher-timescale.sh docker/pg_hba.conf /pgwatch3/

ENV PW3_DATASTORE postgres
ENV PW3_PG_METRIC_STORE_CONN_STR postgresql://pgwatch3:pgwatch3admin@localhost:5432/pgwatch3_metrics
ENV PW3_PG_SCHEMA_TYPE timescale
ENV PW3_AES_GCM_KEYPHRASE_FILE /pgwatch3/persistent-config/default-password-encryption-key.txt

# Admin UI for configuring servers to be monitored
EXPOSE 8080
# Gatherer healthcheck port / metric statistics (JSON)
EXPOSE 8081
# Postgres DB holding the pgwatch3 config DB / metrics
EXPOSE 5432
# Grafana UI
EXPOSE 3000
# Prometheus scraping port
EXPOSE 9187

### Volumes for easier updating to newer to newer pgwatch3 containers
### NB! Backwards compatibility is not 100% guaranteed so a backup
### using traditional means is still recommended before updating - see "Updating to a newer Docker version" from README

VOLUME /pgwatch3/persistent-config
VOLUME /var/lib/postgresql
VOLUME /var/lib/grafana

CMD ["/pgwatch3/docker-launcher-timescale.sh"]
100 changes: 100 additions & 0 deletions docker/docker-launcher-timescale.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/bin/bash

mkdir /var/run/grafana && chown grafana /var/run/grafana

if [ ! -f /pgwatch3/persistent-config/self-signed-ssl.key -o ! -f /pgwatch3/persistent-config/self-signed-ssl.pem ] ; then
openssl req -x509 -newkey rsa:4096 -keyout /pgwatch3/persistent-config/self-signed-ssl.key -out /pgwatch3/persistent-config/self-signed-ssl.pem -days 3650 -nodes -sha256 -subj '/CN=pw2'
cp /pgwatch3/persistent-config/self-signed-ssl.pem /etc/ssl/certs/ssl-cert-snakeoil.pem
cp /pgwatch3/persistent-config/self-signed-ssl.key /etc/ssl/private/ssl-cert-snakeoil.key
chown postgres /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/private/ssl-cert-snakeoil.key
chmod -R 0600 /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/private/ssl-cert-snakeoil.key
chmod -R o+rx /pgwatch3/persistent-config
fi

# enable password encryption by default from v1.8.0
if [ ! -f /pgwatch3/persistent-config/default-password-encryption-key.txt ]; then
echo -n "${RANDOM}${RANDOM}${RANDOM}${RANDOM}" > /pgwatch3/persistent-config/default-password-encryption-key.txt
chmod 0600 /pgwatch3/persistent-config/default-password-encryption-key.txt
fi

GRAFANASSL="${PW3_GRAFANASSL,,}" # to lowercase
if [ "$GRAFANASSL" == "1" ] || [ "${GRAFANASSL:0:1}" == "t" ]; then
$(grep -q 'protocol = http$' /etc/grafana/grafana.ini)
if [ "$?" -eq 0 ] ; then
sed -i 's/protocol = http.*/protocol = https/' /etc/grafana/grafana.ini
fi
fi

if [ -n "$PW3_GRAFANAUSER" ] ; then
sed -i "s/admin_user =.*/admin_user = ${PW3_GRAFANAUSER}/" /etc/grafana/grafana.ini
fi

if [ -n "$PW3_GRAFANAPASSWORD" ] ; then
sed -i "s/admin_password =.*/admin_password = ${PW3_GRAFANAPASSWORD}/" /etc/grafana/grafana.ini
fi

if [ -n "$PW3_GRAFANANOANONYMOUS" ] ; then
CFG=$(cat <<-'HERE'
[auth.anonymous]
enabled = false
HERE
)
echo "$CFG" >> /etc/grafana/grafana.ini
fi

if [ ! -f /pgwatch3/persistent-config/db-bootstrap-done-marker ] ; then

if [ ! -d /var/lib/postgresql/15 ]; then
mkdir /var/lib/postgresql/15 && chown -R postgres:postgres /var/lib/postgresql/15
pg_dropcluster 15 main
pg_createcluster --locale en_US.UTF-8 15 main
echo "include = 'pgwatch_postgresql.conf'" >> /etc/postgresql/15/main/postgresql.conf
cp /pgwatch3/postgresql_timescale.conf /etc/postgresql/15/main/pgwatch_postgresql.conf
cp /pgwatch3/pg_hba.conf /etc/postgresql/15/main/pg_hba.conf
fi

pg_ctlcluster 15 main start -- --wait

su -c "psql -d postgres -f /pgwatch3/bootstrap/change_pw.sql" postgres
su -c "psql -d postgres -f /pgwatch3/bootstrap/grant_monitor_to_pgwatch3.sql" postgres
su -c "psql -d postgres -f /pgwatch3/bootstrap/create_db_pgwatch.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/bootstrap/revoke_public_create.sql" postgres
su -c "psql -d postgres -f /pgwatch3/bootstrap/create_db_grafana.sql" postgres
su -c "psql -d postgres -f /pgwatch3/bootstrap/create_db_metric_store.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/sql/config_store/config_store.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/sql/config_store/metric_definitions.sql" postgres
su -c "psql -d pgwatch3_metrics -f /pgwatch3/sql/metric_store/00_schema_base.sql" postgres
su -c "psql -d pgwatch3_metrics -f /pgwatch3/sql/metric_store/01_old_metrics_cleanup_procedure.sql" postgres

su -c "psql -d pgwatch3_metrics -f /pgwatch3/sql/metric_store/timescale/ensure_partition_timescale.sql" postgres
su -c "psql -d pgwatch3_metrics -f /pgwatch3/sql/metric_store/timescale/change_compression_interval.sql" postgres
su -c "psql -d pgwatch3_metrics -f /pgwatch3/sql/metric_store/timescale/metric_store_timescale.sql" postgres
su -c "psql -d pgwatch3_metrics -f /pgwatch3/sql/metric_store/timescale/change_chunk_interval.sql" postgres
su -c "psql -d pgwatch3_metrics -f /pgwatch3/sql/metric_store/metric-time/ensure_partition_metric_time.sql" postgres

su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_load_average/9.1/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_stat_statements/9.4/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_stat_activity/9.2/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_stat_replication/9.2/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_table_bloat_approx/9.5/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_table_bloat_approx_sql/12/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_wal_size/10/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_psutil_cpu/9.1/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_psutil_mem/9.1/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_psutil_disk/9.1/metric.sql" postgres
su -c "psql -d pgwatch3 -f /pgwatch3/metrics/00_helpers/get_psutil_disk_io_total/9.1/metric.sql" postgres
su -c "psql -d pgwatch3 -c 'create extension pg_qualstats'" postgres

if [ -n "$PW3_TESTDB" ] ; then
su -c "psql -d pgwatch3 -f /pgwatch3/bootstrap/insert_test_monitored_db.sql" postgres
fi

touch /pgwatch3/persistent-config/db-bootstrap-done-marker

pg_ctlcluster 15 main stop -- --wait

fi

sleep 1

exec /usr/local/bin/supervisord --configuration=/etc/supervisor/supervisord.conf --nodaemon
19 changes: 19 additions & 0 deletions docker/postgresql_timescale.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
listen_addresses='*'
shared_buffers='64MB'
work_mem='16MB'
checkpoint_timeout='1h'
ssl=true
track_io_timing=on
shared_preload_libraries = 'pg_stat_statements,timescaledb,pg_qualstats'
track_functions='pl'
wal_compression=zstd
log_destination=csvlog
logging_collector=on
log_directory='/var/log/postgresql'
log_filename='postgresql-%a.log'
log_truncate_on_rotation=on
wal_level=archive
archive_mode=on
archive_command='/bin/true'
max_worker_processes=16
max_locks_per_transaction=128
50 changes: 50 additions & 0 deletions docker/supervisord-timescale.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[supervisord]
nodaemon=true
user=root
pidfile=/var/run/supervisord.pid
logfile=/var/log/supervisor/supervisord.log
childlogdir=/var/log/supervisor

[unix_http_server]
file=/var/run/supervisor.sock

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock

[program:supervisord_bootstrap]
command=/pgwatch3/bootstrap/supervisord_bootstrap_pg.sh
autorestart=false
startsecs=0
autostart=true
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0

[program:postgres]
command=/usr/lib/postgresql/15/bin/postgres -D /var/lib/postgresql/15/main -c config_file=/etc/postgresql/15/main/postgresql.conf
user=postgres
startsecs=0
priority=1
autostart=false

[program:pgwatch3]
command=/pgwatch3/pgwatch3
priority=300
autostart=false

[program:grafana]
command=/usr/sbin/grafana-server --homepath=/usr/share/grafana --pidfile=/var/run/grafana/grafana-server.pid --config=/etc/grafana/grafana.ini --packaging=deb cfg:default.paths.provisioning=/etc/grafana/provisioning cfg:default.paths.data=/var/lib/grafana cfg:default.paths.logs=/var/log/grafana cfg:default.paths.plugins=/var/lib/grafana/plugins
user=grafana
startsecs=0
priority=500
autostart=false

[program:grafana_dashboard_setup]
command=/pgwatch3/bootstrap/set_up_grafana_dashboards_pg.sh
priority=600
autorestart=false
startsecs=0
autostart=false
4 changes: 2 additions & 2 deletions grafana_dashboards/postgres/v8/stat-activity/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select\n $__timeGroup(time, $agg_interval),\n sum((data->>'count')::integer) as \" \",\n data->>'query' as \"query\"\nfrom stat_activity\nwhere dbname = '$dbname' and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then\n not data->>'query' ~* E'/\\\\*\\\\W*pgwatch2_generated\\\\W*\\\\*/'\n else\n true\n end\ngroup by 1,3\norder by 1;\n\n",
"rawSql": "select\n $__timeGroup(time, $agg_interval),\n sum((data->>'count')::integer) as \" \",\n data->>'query' as \"query\"\nfrom stat_activity\nwhere dbname = '$dbname' and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then\n not data->>'query' ~* E'/\\\\*\\\\W*pgwatch3_generated\\\\W*\\\\*/'\n else\n true\n end\ngroup by 1,3\norder by 1;\n\n",
"refId": "A",
"select": [
[
Expand Down Expand Up @@ -205,7 +205,7 @@
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select sum((data->>'count')::integer) as count, data->>'query' as query\nfrom stat_activity\nwhere dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then\n not data->>'query' ~* E'/\\\\*\\\\W*pgwatch2_generated\\\\W*\\\\*/'\n else\n true\n end\ngroup by 2\norder by 1 desc;",
"rawSql": "select sum((data->>'count')::integer) as count, data->>'query' as query\nfrom stat_activity\nwhere dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then\n not data->>'query' ~* E'/\\\\*\\\\W*pgwatch3_generated\\\\W*\\\\*/'\n else\n true\n end\ngroup by 2\norder by 1 desc;",
"refId": "A",
"select": [
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ $$ LANGUAGE plpython3u VOLATILE;
/* contacting S3 could be laggy depending on location */
ALTER FUNCTION get_backup_age_pgbackrest() SET statement_timeout TO '30s';

GRANT EXECUTE ON FUNCTION get_backup_age_pgbackrest() TO pgwatch2;
GRANT EXECUTE ON FUNCTION get_backup_age_pgbackrest() TO pgwatch3;

COMMENT ON FUNCTION get_backup_age_pgbackrest() is 'created for pgwatch2';
COMMENT ON FUNCTION get_backup_age_pgbackrest() is 'created for pgwatch3';
2 changes: 1 addition & 1 deletion src/metrics/stat_activity/11/metric.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
select /* pgwatch2_generated */
select /* pgwatch3_generated */
(extract(epoch from now()) * 1e9)::int8 as epoch_ns,
s.query as query,
count(*) as count
Expand Down
2 changes: 1 addition & 1 deletion src/metrics/stat_activity/11/metric_su.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
select /* pgwatch2_generated */
select /* pgwatch3_generated */
(extract(epoch from now()) * 1e9)::int8 as epoch_ns,
s.query as query,
count(*) as count
Expand Down
6 changes: 3 additions & 3 deletions src/sql/config_store/metric_definitions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5743,7 +5743,7 @@ values (
'subscription_stats',
15,
$sql$
select /* pgwatch2_generated */
select /* pgwatch3_generated */
(extract(epoch from now()) * 1e9)::int8 as epoch_ns,
subname::text as tag_subname,
apply_error_count,
Expand All @@ -5759,7 +5759,7 @@ values (
'stat_activity',
11,
$sql$
select /* pgwatch2_generated */
select /* pgwatch3_generated */
(extract(epoch from now()) * 1e9)::int8 as epoch_ns,
s.query as query,
count(*) as count
Expand All @@ -5772,7 +5772,7 @@ where s.datname = current_database()
group by s.query;
$sql$,
$sql$
select /* pgwatch2_generated */
select /* pgwatch3_generated */
(extract(epoch from now()) * 1e9)::int8 as epoch_ns,
s.query as query,
count(*) as count
Expand Down
2 changes: 1 addition & 1 deletion src/webui/src/layout/Logs/LogGrid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default () => {
2022-12-15 10:31:22,588 INFO 84 172.17.0.1 - - [15/Dec/2022:10:31:22] "GET /static/jquery-3.5.1.min.js HTTP/1.1" 200 89476 "http://localhost:8080/dbs" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
2022-12-15 10:31:22,591 INFO 84 172.17.0.1 - - [15/Dec/2022:10:31:22] "GET /static/logo.png HTTP/1.1" 200 5325 "http://localhost:8080/dbs" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
2022-12-15 10:31:22,739 INFO 84 172.17.0.1 - - [15/Dec/2022:10:31:22] "GET /favicon.ico HTTP/1.1" 200 1406 "http://localhost:8080/dbs" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
2022-12-15 10:31:27,457 INFO 84 172.17.0.1 - - [15/Dec/2022:10:31:27] "GET /logs/pgwatch2/200 HTTP/1.1" 200 - "http://localhost:8080/dbs" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"`
2022-12-15 10:31:27,457 INFO 84 172.17.0.1 - - [15/Dec/2022:10:31:27] "GET /logs/pgwatch3/200 HTTP/1.1" 200 - "http://localhost:8080/dbs" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"`
}
</pre>
</Box>
Expand Down