From 2a5d4f4e0595582dea80ac6587ac022b6e969410 Mon Sep 17 00:00:00 2001 From: Roland Stens Date: Thu, 28 Jan 2021 11:12:27 -0800 Subject: [PATCH] Image updates - First upload --- containers/Patroni-13.1/.gitignore | 33 +++ containers/Patroni-13.1/CONTRIBUTING.md | 9 + containers/Patroni-13.1/Dockerfile | 46 +++ containers/Patroni-13.1/LICENSE | 202 +++++++++++++ containers/Patroni-13.1/README.md | 79 +++++ containers/Patroni-13.1/RELEASE.md | 8 + .../contrib/root/usr/bin/entrypoint.sh | 48 ++++ .../usr/share/scripts/patroni/health_check.sh | 8 + .../root/usr/share/scripts/patroni/init.txt | 7 + .../usr/share/scripts/patroni/post_init.sh | 16 ++ .../openshift/templates/build.yaml | 94 ++++++ containers/Patroni-13.1/samples/README.md | 1 + containers/Patroni-13.1/samples/deploy.yaml | 271 ++++++++++++++++++ .../Patroni-13.1/samples/prerequisite.yaml | 156 ++++++++++ containers/Postgres-13.1/.gitignore | 33 +++ containers/Postgres-13.1/Dockerfile | 42 +++ containers/Postgres-13.1/LICENSE | 201 +++++++++++++ containers/Postgres-13.1/README.md | 2 + containers/Postgres-13.1/RELEASE.md | 8 + .../contrib/root/usr/bin/entrypoint.sh | 8 + .../usr/share/scripts/patroni/health_check.sh | 4 + .../root/usr/share/scripts/patroni/init.txt | 7 + .../usr/share/scripts/patroni/post_init.sh | 16 ++ .../openshift/templates/build.yaml | 94 ++++++ containers/Postgres-13.1/samples/README.md | 1 + containers/Postgres-13.1/samples/deploy.yaml | 271 ++++++++++++++++++ .../Postgres-13.1/samples/prerequisite.yaml | 156 ++++++++++ database/.docker/db/Dockerfile | 4 +- database/.docker/db/create_postgis.sql | 10 +- docker-compose.yml | 57 ++-- 30 files changed, 1864 insertions(+), 28 deletions(-) create mode 100644 containers/Patroni-13.1/.gitignore create mode 100644 containers/Patroni-13.1/CONTRIBUTING.md create mode 100644 containers/Patroni-13.1/Dockerfile create mode 100644 containers/Patroni-13.1/LICENSE create mode 100644 containers/Patroni-13.1/README.md create mode 100644 containers/Patroni-13.1/RELEASE.md create mode 100644 containers/Patroni-13.1/contrib/root/usr/bin/entrypoint.sh create mode 100644 containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/health_check.sh create mode 100644 containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/init.txt create mode 100644 containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/post_init.sh create mode 100644 containers/Patroni-13.1/openshift/templates/build.yaml create mode 100644 containers/Patroni-13.1/samples/README.md create mode 100644 containers/Patroni-13.1/samples/deploy.yaml create mode 100644 containers/Patroni-13.1/samples/prerequisite.yaml create mode 100644 containers/Postgres-13.1/.gitignore create mode 100644 containers/Postgres-13.1/Dockerfile create mode 100644 containers/Postgres-13.1/LICENSE create mode 100644 containers/Postgres-13.1/README.md create mode 100644 containers/Postgres-13.1/RELEASE.md create mode 100644 containers/Postgres-13.1/contrib/root/usr/bin/entrypoint.sh create mode 100644 containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/health_check.sh create mode 100644 containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/init.txt create mode 100644 containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/post_init.sh create mode 100644 containers/Postgres-13.1/openshift/templates/build.yaml create mode 100644 containers/Postgres-13.1/samples/README.md create mode 100644 containers/Postgres-13.1/samples/deploy.yaml create mode 100644 containers/Postgres-13.1/samples/prerequisite.yaml diff --git a/containers/Patroni-13.1/.gitignore b/containers/Patroni-13.1/.gitignore new file mode 100644 index 0000000000..310a436818 --- /dev/null +++ b/containers/Patroni-13.1/.gitignore @@ -0,0 +1,33 @@ +# +.DS_Store +logs +build/ +dist/ +*.pem +.DS_Store +*~ +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +*.zip +*.tgz +*.tar.gz +*.orig + +# These files contain credentials, do not add them to +# the repo. +.env + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# OpenShift +*-secret.yaml +*-secret.json diff --git a/containers/Patroni-13.1/CONTRIBUTING.md b/containers/Patroni-13.1/CONTRIBUTING.md new file mode 100644 index 0000000000..84d6ca3e61 --- /dev/null +++ b/containers/Patroni-13.1/CONTRIBUTING.md @@ -0,0 +1,9 @@ +## How to contribute +Government employees, public and members of the private sector are encouraged to contribute to the repository by **forking and submitting a pull request**. + +(If you are new to GitHub, you might start with a [basic tutorial](https://help.github.com/articles/set-up-git) and check out a more detailed guide to [pull requests](https://help.github.com/articles/using-pull-requests/).) + +Pull requests will be evaluated by the repository guardians on a schedule and if deemed beneficial will be committed to the master. + +All contributors retain the original copyright to their stuff, but by contributing to this project, you grant a world-wide, royalty-free, perpetual, irrevocable, non-exclusive, transferable license to all users **under the terms of the license under which this project is distributed.** + diff --git a/containers/Patroni-13.1/Dockerfile b/containers/Patroni-13.1/Dockerfile new file mode 100644 index 0000000000..42c3069c46 --- /dev/null +++ b/containers/Patroni-13.1/Dockerfile @@ -0,0 +1,46 @@ +FROM postgres:13.1 + +LABEL Alexander Kukushkin + +ENV PATRONI_VERSION=2.0.1 +ENV LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 +ENV PATRONI_HOME=/opt/patroni + +ARG PGHOME=/home/postgres + +RUN export DEBIAN_FRONTEND=noninteractive \ + && set -x \ + && echo 'APT::Install-Recommends "0";\nAPT::Install-Suggests "0";' > /etc/apt/apt.conf.d/01norecommend \ + && apt-get update -y \ + && apt-get install -y curl jq locales git build-essential python3 python3-dev python3-pip python3-wheel python3-setuptools python3-virtualenv + +RUN apt-get install -y pgbadger pg-activity postgis postgresql-13-pgrouting + +RUN echo 'Make sure we have a en_US.UTF-8 locale available' \ + && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 \ + && pip3 --isolated --no-cache-dir install psycopg2-binary \ + && pip3 --isolated --no-cache-dir install "patroni[kubernetes]==${PATRONI_VERSION}" \ + && PGHOME=/home/postgres \ + && mkdir -p $PGHOME \ + && sed -i "s|/var/lib/postgresql.*|$PGHOME:/bin/bash|" /etc/passwd \ + && echo 'Setting permissions for OpenShift' \ + && chmod 664 /etc/passwd \ + && mkdir -p $PGHOME/pgdata/pgroot \ + && chgrp -R 0 $PGHOME \ + && chown -R postgres $PGHOME \ + && chmod -R 775 $PGHOME \ + && echo 'Cleaning up' \ + && apt-get remove -y git build-essential python3-dev python3-pip python3-wheel python3-setuptools \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* /root/.cache + +COPY contrib/root / + +VOLUME /home/postgres/pgdata +USER postgres +WORKDIR /home/postgres + +EXPOSE 5432 8008 + +CMD ["/bin/bash", "/usr/bin/entrypoint.sh"] diff --git a/containers/Patroni-13.1/LICENSE b/containers/Patroni-13.1/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/containers/Patroni-13.1/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/containers/Patroni-13.1/README.md b/containers/Patroni-13.1/README.md new file mode 100644 index 0000000000..fca99fa38b --- /dev/null +++ b/containers/Patroni-13.1/README.md @@ -0,0 +1,79 @@ +# TL;DR + +This repo contains the Platform Service (PS) and community maintained version of PostgreSQL managed by Patroni for High Availability (HA). You will find this image in the `bcgov` namespace on all PS managed clusters. + +```console +oc get is -n bcgov +``` + +You will find a sample of how to deploy the image [here](./samples/README.md). + +# Image Management + +This image is based on PostgreSQL v13.1. It will be periodically rebuilt acording to the `cron` schedule in the workflow. When it is rebuilt, [patch](https://semver.org/) updates as well as operating security fixes will be incorporated and redistributed to all clusters via the [stable tag](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-image-tag-version). + +## Tags + +The stable tag for this image is `13.1`. When the image is rebuilt [patch](https://semver.org/) updates to PostgreSQL will be incorporated along with operating system updates. + +See the [release notes](./RELEASE.md) for more information and any other unique tags. + +## Usage + +Below is a sample of how you might reference this image from a `StatefulSet` deployment manifest. + +```yaml + image: image-registry.openshift-image-registry.svc:5000/af2668-tools/patroni-postgres:13.1 +``` + +Find a sample StatefulSet deployment [here](./samples/README.md). + +**ProTip 🤓** + +Use the **internal** host for the `bcgov` image catalog; if you use the external one (contains gov.bc.ca) you'll need to authenticate. + +# Build + +This image is built as per the [workflow](.github/workflows/image.yaml) and the OpenShift [templates](./openshift/templates). + +## Distribution + +Run RBAC to create an SA and bind it to, this is done on a lab or build cluster: + +```yaml + kind: ClusterRole + name: system:image-puller +``` + +Using the token from the SA above, create a docker registry secret with the appropriate credentials. For the `--docker-server` argument use the **external registry host name**. + +```console +oc create secret docker-registry bcgov-tools-klab \ + --docker-server=image-registry.foo.bar.gov.bc.ca \ + --docker-username=bcgov-images-cicd \ + --docker-password=$SATOKEN \ + --docker-email=unused +``` + +Then allow the builder service account to access the newly minted docker credentials for pulling images: + +```console +oc secrets add sa/builder secrets/bcgov-tools-klab --for=pull +``` + +And finally, create an `imagestreamtag` to import the image to your cluster. Again, for the `-from-image` argument use the **external registry host name**. + +```console +oc create imagestreamtag patroni-postgresql:13.1 \ + --from-image=image-registry.foo.bar.gov.bc.ca /bcgov-tools/patroni-postgresql:13.1 +``` + +Check to make sure it imported: + +```console +oc get is +``` + +```console +oc describe is/patroni-postgresql +``` diff --git a/containers/Patroni-13.1/RELEASE.md b/containers/Patroni-13.1/RELEASE.md new file mode 100644 index 0000000000..508761e030 --- /dev/null +++ b/containers/Patroni-13.1/RELEASE.md @@ -0,0 +1,8 @@ + +## Release Notes and Tags + +image stream: bcgov/patroni-postgres + +| Tag | Description | +| :-----------: | :------------------------------------- | +|13.1 | PostgreSQL v13.1 (latest) with Patroni | diff --git a/containers/Patroni-13.1/contrib/root/usr/bin/entrypoint.sh b/containers/Patroni-13.1/contrib/root/usr/bin/entrypoint.sh new file mode 100644 index 0000000000..23a983ed10 --- /dev/null +++ b/containers/Patroni-13.1/contrib/root/usr/bin/entrypoint.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +if [[ $UID -ge 10000 ]]; then + GID=$(id -g) + sed -e "s/^postgres:x:[^:]*:[^:]*:/postgres:x:$UID:$GID:/" /etc/passwd > /tmp/passwd + cat /tmp/passwd > /etc/passwd + rm /tmp/passwd +fi + +# FIX -> FATAL: data directory "..." has group or world access +mkdir -p "$PATRONI_POSTGRESQL_DATA_DIR" +chmod 700 "$PATRONI_POSTGRESQL_DATA_DIR" + +cat > /home/postgres/patroni.yml <<__EOF__ +bootstrap: + post_bootstrap: /usr/share/scripts/patroni/post_init.sh + dcs: + postgresql: + use_pg_rewind: true + parameters: + max_connections: ${POSTGRESQL_MAX_CONNECTIONS:-100} + max_prepared_transactions: ${POSTGRESQL_MAX_PREPARED_TRANSACTIONS:-0} + max_locks_per_transaction: ${POSTGRESQL_MAX_LOCKS_PER_TRANSACTION:-64} + initdb: + - auth-host: md5 + - auth-local: trust + - encoding: UTF8 + - locale: en_US.UTF-8 + - data-checksums + pg_hba: + - host all all 0.0.0.0/0 md5 + - host replication ${PATRONI_REPLICATION_USERNAME} ${POD_IP}/16 md5 +restapi: + connect_address: '${POD_IP}:8008' +postgresql: + connect_address: '${POD_IP}:5432' + authentication: + superuser: + password: '${PATRONI_SUPERUSER_PASSWORD}' + replication: + password: '${PATRONI_REPLICATION_PASSWORD}' +__EOF__ + +unset PATRONI_SUPERUSER_PASSWORD PATRONI_REPLICATION_PASSWORD +export KUBERNETES_NAMESPACE=$PATRONI_KUBERNETES_NAMESPACE +export POD_NAME=$PATRONI_NAME + +exec /usr/bin/python3 /usr/local/bin/patroni /home/postgres/patroni.yml \ No newline at end of file diff --git a/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/health_check.sh b/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/health_check.sh new file mode 100644 index 0000000000..10af045e46 --- /dev/null +++ b/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/health_check.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -Eeu +set -o pipefail + +# check for disk space. Fails if usage hits above 90% +df "${PATRONI_POSTGRESQL_DATA_DIR:-/home/postgres/pgdata}" --output=pcent | tail -n 1 | awk '{if ($1+0 > 90) exit 1; else exit 0;}' + +pg_isready -q && patronictl list --format=json | jq -e ".[] | select(.Member == \"$(hostname)\" and .State == \"running\")" diff --git a/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/init.txt b/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/init.txt new file mode 100644 index 0000000000..16d8a554a2 --- /dev/null +++ b/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/init.txt @@ -0,0 +1,7 @@ +CREATE EXTENSION postgis; +CREATE EXTENSION postgis_raster; +CREATE EXTENSION postgis_topology; +CREATE EXTENSION postgis_sfcgal; +CREATE EXTENSION pgRouting; +CREATE EXTENSION fuzzystrmatch; +CREATE EXTENSION pgcrypto; diff --git a/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/post_init.sh b/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/post_init.sh new file mode 100644 index 0000000000..fd4b4a6230 --- /dev/null +++ b/containers/Patroni-13.1/contrib/root/usr/share/scripts/patroni/post_init.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -Eeu + +if [[ (! -z "$APP_USER") && (! -z "$APP_PASSWORD") && (! -z "$APP_DATABASE")]]; then + echo "Creating user ${APP_USER}" + psql "$1" -w -c "create user ${APP_USER} WITH LOGIN ENCRYPTED PASSWORD '${APP_PASSWORD}'" + + echo "Creating database ${APP_DATABASE}" + psql "$1" -w -c "CREATE DATABASE ${APP_DATABASE} OWNER ${APP_USER} ENCODING '${APP_DB_ENCODING:-UTF8}' LC_COLLATE = '${APP_DB_LC_COLLATE:-en_US.UTF-8}' LC_CTYPE = '${APP_DB_LC_CTYPE:-en_US.UTF-8}'" + echo "Creating extensions" + #=psql ${APP_DATABASE} "$1" -w -f=init.txt + +else + echo "Skipping user creation" + echo "Skipping database creation" +fi diff --git a/containers/Patroni-13.1/openshift/templates/build.yaml b/containers/Patroni-13.1/openshift/templates/build.yaml new file mode 100644 index 0000000000..ec7080f921 --- /dev/null +++ b/containers/Patroni-13.1/openshift/templates/build.yaml @@ -0,0 +1,94 @@ +# Copyright 2020 The Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: v1 +kind: Template +metadata: + name: patroni +labels: + app: ${NAME} + phase: build + app.kubernetes.io/component: database + app.kubernetes.io/name: patroni + app.kubernetes.io/managed-by: template + app.kubernetes.io/version: "${PG_VERSION}" +parameters: + - name: NAME + value: "patroni-postgres" + - name: OUT_VERSION + description: Ouput version + value: "13.1" + - name: GIT_URI + value: "https://github.com/bcgov/patroni-postgres-container.git" + - name: GIT_REF + value: "master" + - name: PG_VERSION + value: "13.1" +objects: + # Postgres ImageStream is created if it doesn't already exist + - apiVersion: image.openshift.io/v1 + kind: ImageStream + metadata: + name: postgres + spec: + lookupPolicy: + local: false + - apiVersion: v1 + kind: ImageStreamTag + lookupPolicy: + local: false + metadata: + name: postgres:${PG_VERSION} + tag: + from: + kind: DockerImage + name: registry.hub.docker.com/library/postgres:${PG_VERSION} + importPolicy: + scheduled: true + name: "${PG_VERSION}" + referencePolicy: + type: Source + - apiVersion: v1 + kind: ImageStream + metadata: + name: ${NAME} + spec: + lookupPolicy: + local: false + - apiVersion: v1 + kind: BuildConfig + metadata: + name: ${NAME} + spec: + output: + to: + kind: ImageStreamTag + name: "${NAME}:${OUT_VERSION}" + source: + contextDir: / + git: + ref: ${GIT_REF} + uri: ${GIT_URI} + type: Git + strategy: + dockerStrategy: + from: + kind: ImageStreamTag + name: postgres:${PG_VERSION} + type: Docker + triggers: + - type: ConfigChange + - imageChange: {} + type: ImageChange diff --git a/containers/Patroni-13.1/samples/README.md b/containers/Patroni-13.1/samples/README.md new file mode 100644 index 0000000000..a998e79c52 --- /dev/null +++ b/containers/Patroni-13.1/samples/README.md @@ -0,0 +1 @@ +This is a sample deployment for PostgreSQL / Patroni. More docs to follow. \ No newline at end of file diff --git a/containers/Patroni-13.1/samples/deploy.yaml b/containers/Patroni-13.1/samples/deploy.yaml new file mode 100644 index 0000000000..4b173d2dad --- /dev/null +++ b/containers/Patroni-13.1/samples/deploy.yaml @@ -0,0 +1,271 @@ +# Copyright 2020 The Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + annotations: + description: |- + Patroni Postgresql database cluster, with persistent storage. + iconClass: icon-postgresql + openshift.io/display-name: Patroni Postgresql (Persistent) + openshift.io/long-description: This template deploys a patroni postgresql HA + cluster with persistent storage. + tags: postgresql + name: patroni-pgsql-persistent +labels: + app: ${NAME} + phase: deploy + app.kubernetes.io/instance: ${NAME} + app.kubernetes.io/component: database + app.kubernetes.io/name: patroni + app.kubernetes.io/managed-by: template +objects: + - apiVersion: v1 + kind: Service + metadata: + creationTimestamp: null + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME}-master + spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + cluster-name: ${NAME} + role: master + app.kubernetes.io/name: patroni + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} + - apiVersion: apps/v1 + kind: StatefulSet + metadata: + creationTimestamp: null + generation: 3 + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME} + spec: + podManagementPolicy: OrderedReady + replicas: ${{REPLICAS}} + revisionHistoryLimit: 10 + selector: + matchLabels: + statefulset: ${NAME} + serviceName: ${NAME} + template: + metadata: + creationTimestamp: null + labels: + app: ${NAME} + statefulset: ${NAME} + cluster-name: ${NAME} + app.kubernetes.io/name: patroni + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: statefulset + operator: In + values: + - ${NAME} + topologyKey: "kubernetes.io/hostname" + containers: + - env: + #TODO: Remove POD_IP in favor of PATRONI_KUBERNETES_POD_IP + - name: POD_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + # - name: PATRONI_KUBERNETES_USE_ENDPOINTS + # value: 'true' + # - name: PATRONI_KUBERNETES_POD_IP + # valueFrom: + # fieldRef: + # apiVersion: v1 + # fieldPath: status.podIP + # - name: PATRONI_KUBERNETES_PORTS + # value: '{[{"name": "postgresql", "port": 5432}]}' + - name: PATRONI_KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: PATRONI_KUBERNETES_LABELS + value: '{"cluster-name": "${NAME}", "app.kubernetes.io/name": "patroni"}' + - name: PATRONI_SUPERUSER_USERNAME + valueFrom: + secretKeyRef: + key: superuser-username + name: ${NAME}-creds + - name: PATRONI_SUPERUSER_PASSWORD + valueFrom: + secretKeyRef: + key: superuser-password + name: ${NAME}-creds + - name: PATRONI_REPLICATION_USERNAME + valueFrom: + secretKeyRef: + key: replication-username + name: ${NAME}-creds + - name: PATRONI_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + key: replication-password + name: ${NAME}-creds + - name: APP_USER + valueFrom: + secretKeyRef: + key: app-db-username + name: ${NAME}-creds + - name: APP_PASSWORD + valueFrom: + secretKeyRef: + key: app-db-password + name: ${NAME}-creds + - name: APP_DATABASE + valueFrom: + secretKeyRef: + key: app-db-name + name: ${NAME}-creds + - name: PATRONI_SCOPE + value: ${NAME} + - name: PATRONI_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: PATRONI_LOG_LEVEL + value: WARNING + - name: PATRONI_POSTGRESQL_DATA_DIR + value: /home/postgres/pgdata/pgroot/data + - name: PATRONI_POSTGRESQL_PGPASS + value: /tmp/pgpass + - name: PATRONI_POSTGRESQL_LISTEN + value: 0.0.0.0:5432 + - name: PATRONI_RESTAPI_LISTEN + value: 0.0.0.0:8008 + image: ${IMAGE_REGISTRY}/${IMAGE_STREAM_NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG} + # Because we are using image reference to a tag, we need to always + # pull the image otherwise we end up with outdated/out-of-sync + # image depending on the node where it is running + imagePullPolicy: Always + name: postgresql + ports: + - containerPort: 8008 + protocol: TCP + - containerPort: 5432 + protocol: TCP + resources: + requests: + cpu: ${CPU_REQUEST} + memory: ${MEMORY_REQUEST} + limits: + cpu: ${CPU_LIMIT} + memory: ${MEMORY_LIMIT} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + readinessProbe: + initialDelaySeconds: 5 + timeoutSeconds: 5 + failureThreshold: 4 + exec: + command: + - /usr/share/scripts/patroni/health_check.sh + volumeMounts: + - mountPath: /home/postgres/pgdata + name: postgresql + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + serviceAccountName: ${NAME} + terminationGracePeriodSeconds: 0 + updateStrategy: + type: RollingUpdate + volumeClaimTemplates: + - metadata: + annotations: + volume.beta.kubernetes.io/storage-class: ${STORAGE_CLASS} + labels: + app: ${NAME} + name: postgresql + spec: + storageClassName: ${STORAGE_CLASS} + accessModes: + - ReadWriteOnce + resources: + requests: + storage: ${PVC_SIZE} +parameters: + - name: NAME + description: | + The name of the application for labelling all artifacts. + displayName: Application Name + value: mycool-app-patroni + - name: REPLICAS + description: | + The number of StatefulSet replicas to use. + displayName: REPLICAS + value: "3" + - name: CPU_REQUEST + description: | + Starting amount of CPU the container can use. + displayName: CPU REQUEST + value: "250m" + - name: CPU_LIMIT + description: Maximum amount of CPU the container can use. + displayName: CPU Limit + value: "1" + - name: MEMORY_REQUEST + description: Starting amount of memory the container can use. + displayName: Memory Request + value: 512Mi + - name: MEMORY_LIMIT + description: Maximum amount of memory the container can use. + displayName: Memory Limit + value: 512Mi + - name: IMAGE_STREAM_NAMESPACE + description: | + The OpenShift Namespace where the patroni and postgresql + ImageStream resides. + displayName: ImageStream Namespace + value: af2668-tools + - name: IMAGE_NAME + description: | + The Patroni image stream name + value: patroni-postgres + - name: IMAGE_TAG + description: | + The image tag used to specify which image you would like deployed. + Don't use `latest`. + value: "13.1" + - name: PVC_SIZE + description: The size of the persistent volume to create. + displayName: Persistent Volume Size + value: 1Gi + - name: STORAGE_CLASS + value: netapp-file-standard + - name: IMAGE_REGISTRY + value: image-registry.openshift-image-registry.svc:5000 diff --git a/containers/Patroni-13.1/samples/prerequisite.yaml b/containers/Patroni-13.1/samples/prerequisite.yaml new file mode 100644 index 0000000000..f1cc434a85 --- /dev/null +++ b/containers/Patroni-13.1/samples/prerequisite.yaml @@ -0,0 +1,156 @@ +# Copyright 2020 The Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + annotations: + description: |- + Patroni Postgresql database cluster (prerequisites) + iconClass: icon-postgresql + openshift.io/display-name: Patroni Postgresql prerequisites + openshift.io/long-description: This template deploys patroni prerequisites for an HA DB (secret, service account, role) + tags: postgresql + name: patroni-pgsql-pre-requisite +labels: + app.kubernetes.io/component: database + app.kubernetes.io/name: patroni + app.kubernetes.io/managed-by: template +objects: + - apiVersion: v1 + kind: Secret + metadata: + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME}-creds + stringData: + replication-username: ${PATRONI_REPLICATION_USERNAME} + replication-password: ${PATRONI_REPLICATION_PASSWORD} + superuser-username: ${PATRONI_SUPERUSER_USERNAME} + superuser-password: ${PATRONI_SUPERUSER_PASSWORD} + app-db-name: ${APP_DB_NAME} + app-db-username: app_api_${APP_DB_USERNAME} + app-db-password: ${APP_DB_PASSWORD} + - apiVersion: v1 + kind: ServiceAccount + metadata: + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME} + - apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME} + rules: + - apiGroups: + - "" + resources: + - services + verbs: + - create + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get + - patch + - update + - create + - list + - watch + - delete + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - patch + - update + - watch + - apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME} + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ${NAME} + subjects: + - kind: ServiceAccount + name: ${NAME} +parameters: + - name: NAME + description: | + The name of the application for labelling all artifacts. + displayName: Application Name + value: mycool-app-patroni + - name: PATRONI_SUPERUSER_USERNAME + description: | + Username of the superuser account for initialization. + displayName: Superuser Username + value: postgres + - name: PATRONI_SUPERUSER_PASSWORD + description: | + Password of the superuser account for initialization. + displayName: Superuser Password + generate: expression + from: "[a-z0-9]{32}" + - name: PATRONI_REPLICATION_USERNAME + description: | + Username of the replication account for initialization. + displayName: Replication Username + value: replication + - name: PATRONI_REPLICATION_PASSWORD + description: Password of the replication account for initialization. + displayName: Replication Password + generate: expression + from: "[a-z0-9]{32}" + - name: APP_DB_USERNAME + generate: expression + from: "[a-z0-9]{8}" + - name: APP_DB_NAME + value: registry + - name: APP_DB_PASSWORD + generate: expression + from: "[a-z0-9]{32}" diff --git a/containers/Postgres-13.1/.gitignore b/containers/Postgres-13.1/.gitignore new file mode 100644 index 0000000000..310a436818 --- /dev/null +++ b/containers/Postgres-13.1/.gitignore @@ -0,0 +1,33 @@ +# +.DS_Store +logs +build/ +dist/ +*.pem +.DS_Store +*~ +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +*.zip +*.tgz +*.tar.gz +*.orig + +# These files contain credentials, do not add them to +# the repo. +.env + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# OpenShift +*-secret.yaml +*-secret.json diff --git a/containers/Postgres-13.1/Dockerfile b/containers/Postgres-13.1/Dockerfile new file mode 100644 index 0000000000..aab1356604 --- /dev/null +++ b/containers/Postgres-13.1/Dockerfile @@ -0,0 +1,42 @@ +FROM postgres:13.1 + +LABEL BioHubBC Postgres + +ENV LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 + +ARG PGHOME=/home/postgres + +RUN export DEBIAN_FRONTEND=noninteractive \ + && set -x \ + && echo 'APT::Install-Recommends "0";\nAPT::Install-Suggests "0";' > /etc/apt/apt.conf.d/01norecommend \ + && apt-get update -y \ + && apt-get install -y curl jq locales git build-essential python3 python3-dev python3-pip python3-wheel python3-setuptools python3-virtualenv \ + && apt-get install -y pgbadger pg-activity postgis postgresql-13-pgrouting + +RUN echo 'Make sure we have a en_US.UTF-8 locale available' \ + && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 \ + && pip3 --isolated --no-cache-dir install psycopg2-binary \ + && PGHOME=/home/postgres \ + && mkdir -p $PGHOME \ + && sed -i "s|/var/lib/postgresql.*|$PGHOME:/bin/bash|" /etc/passwd \ + && echo 'Setting permissions for OpenShift' \ + && chmod 664 /etc/passwd \ + && mkdir -p $PGHOME/pgdata/pgroot \ + && chgrp -R 0 $PGHOME \ + && chown -R postgres $PGHOME \ + && chmod -R 775 $PGHOME \ + && echo 'Cleaning up' \ + && apt-get remove -y git build-essential python3-dev python3-pip python3-wheel python3-setuptools \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* /root/.cache + +COPY contrib/root / + +VOLUME /home/postgres/pgdata +USER postgres +WORKDIR /home/postgres + +EXPOSE 5432 + +CMD ["/bin/bash", "/usr/bin/entrypoint.sh"] diff --git a/containers/Postgres-13.1/LICENSE b/containers/Postgres-13.1/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/containers/Postgres-13.1/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/containers/Postgres-13.1/README.md b/containers/Postgres-13.1/README.md new file mode 100644 index 0000000000..041e013e07 --- /dev/null +++ b/containers/Postgres-13.1/README.md @@ -0,0 +1,2 @@ +# postgres-postgis +Temp repo for image build diff --git a/containers/Postgres-13.1/RELEASE.md b/containers/Postgres-13.1/RELEASE.md new file mode 100644 index 0000000000..508761e030 --- /dev/null +++ b/containers/Postgres-13.1/RELEASE.md @@ -0,0 +1,8 @@ + +## Release Notes and Tags + +image stream: bcgov/patroni-postgres + +| Tag | Description | +| :-----------: | :------------------------------------- | +|13.1 | PostgreSQL v13.1 (latest) with Patroni | diff --git a/containers/Postgres-13.1/contrib/root/usr/bin/entrypoint.sh b/containers/Postgres-13.1/contrib/root/usr/bin/entrypoint.sh new file mode 100644 index 0000000000..6152a43f68 --- /dev/null +++ b/containers/Postgres-13.1/contrib/root/usr/bin/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [[ $UID -ge 10000 ]]; then + GID=$(id -g) + sed -e "s/^postgres:x:[^:]*:[^:]*:/postgres:x:$UID:$GID:/" /etc/passwd > /tmp/passwd + cat /tmp/passwd > /etc/passwd + rm /tmp/passwd +fi \ No newline at end of file diff --git a/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/health_check.sh b/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/health_check.sh new file mode 100644 index 0000000000..505f5e1906 --- /dev/null +++ b/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/health_check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -Eeu +set -o pipefail + diff --git a/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/init.txt b/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/init.txt new file mode 100644 index 0000000000..16d8a554a2 --- /dev/null +++ b/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/init.txt @@ -0,0 +1,7 @@ +CREATE EXTENSION postgis; +CREATE EXTENSION postgis_raster; +CREATE EXTENSION postgis_topology; +CREATE EXTENSION postgis_sfcgal; +CREATE EXTENSION pgRouting; +CREATE EXTENSION fuzzystrmatch; +CREATE EXTENSION pgcrypto; diff --git a/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/post_init.sh b/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/post_init.sh new file mode 100644 index 0000000000..fd4b4a6230 --- /dev/null +++ b/containers/Postgres-13.1/contrib/root/usr/share/scripts/patroni/post_init.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -Eeu + +if [[ (! -z "$APP_USER") && (! -z "$APP_PASSWORD") && (! -z "$APP_DATABASE")]]; then + echo "Creating user ${APP_USER}" + psql "$1" -w -c "create user ${APP_USER} WITH LOGIN ENCRYPTED PASSWORD '${APP_PASSWORD}'" + + echo "Creating database ${APP_DATABASE}" + psql "$1" -w -c "CREATE DATABASE ${APP_DATABASE} OWNER ${APP_USER} ENCODING '${APP_DB_ENCODING:-UTF8}' LC_COLLATE = '${APP_DB_LC_COLLATE:-en_US.UTF-8}' LC_CTYPE = '${APP_DB_LC_CTYPE:-en_US.UTF-8}'" + echo "Creating extensions" + #=psql ${APP_DATABASE} "$1" -w -f=init.txt + +else + echo "Skipping user creation" + echo "Skipping database creation" +fi diff --git a/containers/Postgres-13.1/openshift/templates/build.yaml b/containers/Postgres-13.1/openshift/templates/build.yaml new file mode 100644 index 0000000000..73ce757993 --- /dev/null +++ b/containers/Postgres-13.1/openshift/templates/build.yaml @@ -0,0 +1,94 @@ +# Copyright 2020 The Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + name: postgres-postgis build +labels: + app: ${NAME} + phase: build + app.kubernetes.io/component: database + app.kubernetes.io/name: postgres-postgis + app.kubernetes.io/managed-by: template + app.kubernetes.io/version: "${PG_VERSION}" +parameters: + - name: NAME + value: "postgres-postgis" + - name: OUT_VERSION + description: Ouput version + value: "13.1" + - name: GIT_URI + value: "https://github.com/rstens/postgres-postgis.git" + - name: GIT_REF + value: "master" + - name: PG_VERSION + value: "13.1" +objects: + # Postgres ImageStream is created if it doesn't already exist + - apiVersion: image.openshift.io/v1 + kind: ImageStream + metadata: + name: postgres + spec: + lookupPolicy: + local: false + - apiVersion: v1 + kind: ImageStreamTag + lookupPolicy: + local: false + metadata: + name: postgres:${PG_VERSION} + tag: + from: + kind: DockerImage + name: registry.hub.docker.com/library/postgres:${PG_VERSION} + importPolicy: + scheduled: true + name: "${PG_VERSION}" + referencePolicy: + type: Source + - apiVersion: v1 + kind: ImageStream + metadata: + name: ${NAME} + spec: + lookupPolicy: + local: false + - apiVersion: v1 + kind: BuildConfig + metadata: + name: ${NAME} + spec: + output: + to: + kind: ImageStreamTag + name: "${NAME}:${OUT_VERSION}" + source: + contextDir: / + git: + ref: ${GIT_REF} + uri: ${GIT_URI} + type: Git + strategy: + dockerStrategy: + from: + kind: ImageStreamTag + name: postgres:${PG_VERSION} + type: Docker + triggers: + - type: ConfigChange + - imageChange: {} + type: ImageChange diff --git a/containers/Postgres-13.1/samples/README.md b/containers/Postgres-13.1/samples/README.md new file mode 100644 index 0000000000..a998e79c52 --- /dev/null +++ b/containers/Postgres-13.1/samples/README.md @@ -0,0 +1 @@ +This is a sample deployment for PostgreSQL / Patroni. More docs to follow. \ No newline at end of file diff --git a/containers/Postgres-13.1/samples/deploy.yaml b/containers/Postgres-13.1/samples/deploy.yaml new file mode 100644 index 0000000000..4b173d2dad --- /dev/null +++ b/containers/Postgres-13.1/samples/deploy.yaml @@ -0,0 +1,271 @@ +# Copyright 2020 The Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + annotations: + description: |- + Patroni Postgresql database cluster, with persistent storage. + iconClass: icon-postgresql + openshift.io/display-name: Patroni Postgresql (Persistent) + openshift.io/long-description: This template deploys a patroni postgresql HA + cluster with persistent storage. + tags: postgresql + name: patroni-pgsql-persistent +labels: + app: ${NAME} + phase: deploy + app.kubernetes.io/instance: ${NAME} + app.kubernetes.io/component: database + app.kubernetes.io/name: patroni + app.kubernetes.io/managed-by: template +objects: + - apiVersion: v1 + kind: Service + metadata: + creationTimestamp: null + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME}-master + spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + cluster-name: ${NAME} + role: master + app.kubernetes.io/name: patroni + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} + - apiVersion: apps/v1 + kind: StatefulSet + metadata: + creationTimestamp: null + generation: 3 + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME} + spec: + podManagementPolicy: OrderedReady + replicas: ${{REPLICAS}} + revisionHistoryLimit: 10 + selector: + matchLabels: + statefulset: ${NAME} + serviceName: ${NAME} + template: + metadata: + creationTimestamp: null + labels: + app: ${NAME} + statefulset: ${NAME} + cluster-name: ${NAME} + app.kubernetes.io/name: patroni + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: statefulset + operator: In + values: + - ${NAME} + topologyKey: "kubernetes.io/hostname" + containers: + - env: + #TODO: Remove POD_IP in favor of PATRONI_KUBERNETES_POD_IP + - name: POD_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + # - name: PATRONI_KUBERNETES_USE_ENDPOINTS + # value: 'true' + # - name: PATRONI_KUBERNETES_POD_IP + # valueFrom: + # fieldRef: + # apiVersion: v1 + # fieldPath: status.podIP + # - name: PATRONI_KUBERNETES_PORTS + # value: '{[{"name": "postgresql", "port": 5432}]}' + - name: PATRONI_KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: PATRONI_KUBERNETES_LABELS + value: '{"cluster-name": "${NAME}", "app.kubernetes.io/name": "patroni"}' + - name: PATRONI_SUPERUSER_USERNAME + valueFrom: + secretKeyRef: + key: superuser-username + name: ${NAME}-creds + - name: PATRONI_SUPERUSER_PASSWORD + valueFrom: + secretKeyRef: + key: superuser-password + name: ${NAME}-creds + - name: PATRONI_REPLICATION_USERNAME + valueFrom: + secretKeyRef: + key: replication-username + name: ${NAME}-creds + - name: PATRONI_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + key: replication-password + name: ${NAME}-creds + - name: APP_USER + valueFrom: + secretKeyRef: + key: app-db-username + name: ${NAME}-creds + - name: APP_PASSWORD + valueFrom: + secretKeyRef: + key: app-db-password + name: ${NAME}-creds + - name: APP_DATABASE + valueFrom: + secretKeyRef: + key: app-db-name + name: ${NAME}-creds + - name: PATRONI_SCOPE + value: ${NAME} + - name: PATRONI_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: PATRONI_LOG_LEVEL + value: WARNING + - name: PATRONI_POSTGRESQL_DATA_DIR + value: /home/postgres/pgdata/pgroot/data + - name: PATRONI_POSTGRESQL_PGPASS + value: /tmp/pgpass + - name: PATRONI_POSTGRESQL_LISTEN + value: 0.0.0.0:5432 + - name: PATRONI_RESTAPI_LISTEN + value: 0.0.0.0:8008 + image: ${IMAGE_REGISTRY}/${IMAGE_STREAM_NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG} + # Because we are using image reference to a tag, we need to always + # pull the image otherwise we end up with outdated/out-of-sync + # image depending on the node where it is running + imagePullPolicy: Always + name: postgresql + ports: + - containerPort: 8008 + protocol: TCP + - containerPort: 5432 + protocol: TCP + resources: + requests: + cpu: ${CPU_REQUEST} + memory: ${MEMORY_REQUEST} + limits: + cpu: ${CPU_LIMIT} + memory: ${MEMORY_LIMIT} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + readinessProbe: + initialDelaySeconds: 5 + timeoutSeconds: 5 + failureThreshold: 4 + exec: + command: + - /usr/share/scripts/patroni/health_check.sh + volumeMounts: + - mountPath: /home/postgres/pgdata + name: postgresql + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + serviceAccountName: ${NAME} + terminationGracePeriodSeconds: 0 + updateStrategy: + type: RollingUpdate + volumeClaimTemplates: + - metadata: + annotations: + volume.beta.kubernetes.io/storage-class: ${STORAGE_CLASS} + labels: + app: ${NAME} + name: postgresql + spec: + storageClassName: ${STORAGE_CLASS} + accessModes: + - ReadWriteOnce + resources: + requests: + storage: ${PVC_SIZE} +parameters: + - name: NAME + description: | + The name of the application for labelling all artifacts. + displayName: Application Name + value: mycool-app-patroni + - name: REPLICAS + description: | + The number of StatefulSet replicas to use. + displayName: REPLICAS + value: "3" + - name: CPU_REQUEST + description: | + Starting amount of CPU the container can use. + displayName: CPU REQUEST + value: "250m" + - name: CPU_LIMIT + description: Maximum amount of CPU the container can use. + displayName: CPU Limit + value: "1" + - name: MEMORY_REQUEST + description: Starting amount of memory the container can use. + displayName: Memory Request + value: 512Mi + - name: MEMORY_LIMIT + description: Maximum amount of memory the container can use. + displayName: Memory Limit + value: 512Mi + - name: IMAGE_STREAM_NAMESPACE + description: | + The OpenShift Namespace where the patroni and postgresql + ImageStream resides. + displayName: ImageStream Namespace + value: af2668-tools + - name: IMAGE_NAME + description: | + The Patroni image stream name + value: patroni-postgres + - name: IMAGE_TAG + description: | + The image tag used to specify which image you would like deployed. + Don't use `latest`. + value: "13.1" + - name: PVC_SIZE + description: The size of the persistent volume to create. + displayName: Persistent Volume Size + value: 1Gi + - name: STORAGE_CLASS + value: netapp-file-standard + - name: IMAGE_REGISTRY + value: image-registry.openshift-image-registry.svc:5000 diff --git a/containers/Postgres-13.1/samples/prerequisite.yaml b/containers/Postgres-13.1/samples/prerequisite.yaml new file mode 100644 index 0000000000..f1cc434a85 --- /dev/null +++ b/containers/Postgres-13.1/samples/prerequisite.yaml @@ -0,0 +1,156 @@ +# Copyright 2020 The Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + annotations: + description: |- + Patroni Postgresql database cluster (prerequisites) + iconClass: icon-postgresql + openshift.io/display-name: Patroni Postgresql prerequisites + openshift.io/long-description: This template deploys patroni prerequisites for an HA DB (secret, service account, role) + tags: postgresql + name: patroni-pgsql-pre-requisite +labels: + app.kubernetes.io/component: database + app.kubernetes.io/name: patroni + app.kubernetes.io/managed-by: template +objects: + - apiVersion: v1 + kind: Secret + metadata: + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME}-creds + stringData: + replication-username: ${PATRONI_REPLICATION_USERNAME} + replication-password: ${PATRONI_REPLICATION_PASSWORD} + superuser-username: ${PATRONI_SUPERUSER_USERNAME} + superuser-password: ${PATRONI_SUPERUSER_PASSWORD} + app-db-name: ${APP_DB_NAME} + app-db-username: app_api_${APP_DB_USERNAME} + app-db-password: ${APP_DB_PASSWORD} + - apiVersion: v1 + kind: ServiceAccount + metadata: + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME} + - apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME} + rules: + - apiGroups: + - "" + resources: + - services + verbs: + - create + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get + - patch + - update + - create + - list + - watch + - delete + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - patch + - update + - watch + - apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + labels: + app: ${NAME} + cluster-name: ${NAME} + name: ${NAME} + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ${NAME} + subjects: + - kind: ServiceAccount + name: ${NAME} +parameters: + - name: NAME + description: | + The name of the application for labelling all artifacts. + displayName: Application Name + value: mycool-app-patroni + - name: PATRONI_SUPERUSER_USERNAME + description: | + Username of the superuser account for initialization. + displayName: Superuser Username + value: postgres + - name: PATRONI_SUPERUSER_PASSWORD + description: | + Password of the superuser account for initialization. + displayName: Superuser Password + generate: expression + from: "[a-z0-9]{32}" + - name: PATRONI_REPLICATION_USERNAME + description: | + Username of the replication account for initialization. + displayName: Replication Username + value: replication + - name: PATRONI_REPLICATION_PASSWORD + description: Password of the replication account for initialization. + displayName: Replication Password + generate: expression + from: "[a-z0-9]{32}" + - name: APP_DB_USERNAME + generate: expression + from: "[a-z0-9]{8}" + - name: APP_DB_NAME + value: registry + - name: APP_DB_PASSWORD + generate: expression + from: "[a-z0-9]{32}" diff --git a/database/.docker/db/Dockerfile b/database/.docker/db/Dockerfile index a3ba859f3e..966fc08ab0 100644 --- a/database/.docker/db/Dockerfile +++ b/database/.docker/db/Dockerfile @@ -1,4 +1,4 @@ -FROM postgres:12 +FROM postgres:13.1 # set variables ENV POSTGISV 3 @@ -13,7 +13,9 @@ RUN apt-get -qq install -y --no-install-recommends postgresql-$PG_MAJOR-postgis- RUN apt-get -qq install -y --no-install-recommends postgresql-$PG_MAJOR-pgrouting RUN apt-get -qq install -y --no-install-recommends postgresql-$PG_MAJOR-pgrouting-scripts RUN apt-get -qq install -y --no-install-recommends postgresql-server-dev-$PG_MAJOR +RUN apt-get -qq install -y --no-install-recommends pgbadger pg-activity RUN apt-get -qq purge -y --auto-remove postgresql-server-dev-$PG_MAJOR +RUN apt-get -qq autoremove -y RUN apt-get -qq clean # set time zone diff --git a/database/.docker/db/create_postgis.sql b/database/.docker/db/create_postgis.sql index bfdaa71db1..457f61db50 100644 --- a/database/.docker/db/create_postgis.sql +++ b/database/.docker/db/create_postgis.sql @@ -1,5 +1,13 @@ -- Enable PostGIS (includes raster) CREATE EXTENSION IF NOT EXISTS postgis; +CREATE EXTENSION IF NOT EXISTS postgis_raster; --- Enable Topology +-- Enable Topology and Routing CREATE EXTENSION IF NOT EXISTS postgis_topology; +CREATE EXTENSION IF NOT EXISTS postgis_sfcgal; +CREATE EXTENSION IF NOT EXISTS pgRouting; + +-- Enable Helper functions +CREATE EXTENSION IF NOT EXISTS fuzzystrmatch; +CREATE EXTENSION IF NOT EXISTS pgcrypto; + diff --git a/docker-compose.yml b/docker-compose.yml index d18467f685..8a281e9a82 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,11 @@ services: dockerfile: Dockerfile ports: - ${DB_PORT}:${DB_PORT} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 30s + timeout: 10s + retries: 5 environment: - NODE_ENV=${NODE_ENV} - POSTGRES_USER=${DB_USER} @@ -21,32 +26,6 @@ services: volumes: - postgres:/var/lib/postgresql/data - ## Run the database migrations and seeding - db_setup: - image: ${DOCKER_PROJECT_NAME}-db-${DOCKER_NAMESPACE}-setup-img - container_name: ${DOCKER_PROJECT_NAME}-db-${DOCKER_NAMESPACE}-setup-container - build: - context: ./database - dockerfile: ./.docker/db/Dockerfile.setup - environment: - - NODE_ENV=${NODE_ENV} - - DB_HOST=${DB_HOST} - - DB_USER=${DB_USER} - - DB_PASS=${DB_PASS} - - DB_PORT=${DB_PORT} - - DB_DATABASE=${DB_DATABASE} - - DB_SCHEMA=${DB_SCHEMA} - - DB_USER_API=${DB_USER_API} - - DB_SCHEMA_DAPI_V1=${DB_SCHEMA_DAPI_V1} - volumes: - - /opt/app-root/src/node_modules # prevents local node_modules overriding container node_modules - networks: - - local-network - depends_on: - - db - command: - ["./.docker/wait-for-it.sh", "db:${DB_PORT}", "--", "npm", "run", "setup"] - ## Build the api docker image api: image: ${DOCKER_PROJECT_NAME}-api-${DOCKER_NAMESPACE}-img @@ -143,6 +122,32 @@ services: depends_on: - api + ## Run the database migrations and seeding + db_setup: + image: ${DOCKER_PROJECT_NAME}-db-${DOCKER_NAMESPACE}-setup-img + container_name: ${DOCKER_PROJECT_NAME}-db-${DOCKER_NAMESPACE}-setup-container + build: + context: ./database + dockerfile: ./.docker/db/Dockerfile.setup + environment: + - NODE_ENV=${NODE_ENV} + - DB_HOST=${DB_HOST} + - DB_USER=${DB_USER} + - DB_PASS=${DB_PASS} + - DB_PORT=${DB_PORT} + - DB_DATABASE=${DB_DATABASE} + - DB_SCHEMA=${DB_SCHEMA} + - DB_USER_API=${DB_USER_API} + - DB_SCHEMA_DAPI_V1=${DB_SCHEMA_DAPI_V1} + volumes: + - /opt/app-root/src/node_modules # prevents local node_modules overriding container node_modules + networks: + - local-network + depends_on: + db: + condition: service_healthy + command: ["npm", "run", "setup"] + networks: local-network: driver: bridge