diff --git a/.dockerignore b/.dockerignore deleted file mode 120000 index 3e4e48b0..00000000 --- a/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -.gitignore \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..d48a12a1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.github +.venv +venv +.docs +sample +.env \ No newline at end of file diff --git a/.example.env b/.example.env new file mode 100644 index 00000000..7bc47145 --- /dev/null +++ b/.example.env @@ -0,0 +1,18 @@ +## Example environment file for docker-compose and builders + +COMPOSE_PROJECT_NAME=postgis + +## For build arguments +DISTRO=debian +IMAGE_VERSION=bullseye +IMAGE_VARIANT=slim +# Set GENERATE_ALL_LOCALE to empty value or 0 to build just default LOCALE: en_US.UTF-8 +GENERATE_ALL_LOCALE=1 +# Set the language if you need to specify LANG locale at build time +LANG=en_US.UTF-8 +# locale filter to include in the locale generator +LANGS="en_US.UTF-8,id_ID.UTF-8" + +POSTGRES_MAJOR_VERSION=13 +POSTGIS_MAJOR_VERSION=3 +POSTGIS_MINOR_RELEASE=1 diff --git a/.github/workflows/build-latest.yaml b/.github/workflows/build-latest.yaml new file mode 100644 index 00000000..14b52fca --- /dev/null +++ b/.github/workflows/build-latest.yaml @@ -0,0 +1,144 @@ +name: build-latest +on: +# workflow_dispatch: +# inputs: +# distro: +# description: Base image distro +# required: true +# default: debian +# imageVersion: +# description: Base distro image version/release +# required: true +# default: bullseye +# imageVariant: +# description: Base image variant +# required: true +# default: slim + workflow_dispatch: + pull_request: + branches: + - 13.0 + push: + branches: + - 13.0 +jobs: + run-scenario-tests: + runs-on: ubuntu-latest + strategy: + matrix: + postgresMajorVersion: + - 13 + postgisMajorVersion: + - 3 + postgisMinorRelease: + - 1 + scenario: + - datadir_init + - streaming_replication + - collations + - extensions + - logical_replication + include: + - distro: debian + imageVersion: bullseye + imageVariant: slim + steps: + - uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Build image for testing + id: docker_build_testing_image + uses: docker/build-push-action@v2 + with: + context: . + file: Dockerfile + push: false + load: true + tags: kartoza/postgis:manual-build + build-args: | + DISTRO=${{ matrix.distro }} + IMAGE_VERSION=${{ matrix.imageVersion }} + IMAGE_VARIANT=${{ matrix.imageVariant }} + LANGS=en_US.UTF-8,id_ID.UTF-8 + GENERATE_ALL_LOCALE=0 + POSTGRES_MAJOR_VERSION=${{ matrix.postgresMajorVersion }} + POSTGIS_MAJOR_VERSION=${{ matrix.postgisMajorVersion }} + POSTGIS_MINOR_VERSION=${{ matrix.postgresMinorVersion }} + cache-from: | + type=gha,scope=test + type=gha,scope=prod + type=gha,scope=base + cache-to: type=gha,scope=test + target: postgis-test + + - name: Run scenario test ${{ matrix.scenario }} + working-directory: scenario_tests/${{ matrix.scenario }} + env: + COMPOSE_INTERACTIVE_NO_CLI: 1 + PRINT_TEST_LOGS: 1 + run: | + bash ./test.sh + + push-internal-pr-images: + if: github.event_name == 'pull_request' && github.event.pull_request.base.repo.url == github.event.pull_request.head.repo.url + runs-on: ubuntu-latest + needs: [ run-scenario-tests ] + strategy: + matrix: + postgresMajorVersion: + - 13 + postgisMajorVersion: + - 3 + postgisMinorRelease: + - 1 + include: + - distro: debian + imageVersion: bullseye + imageVariant: slim + steps: + - uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + - name: Docker meta + id: docker_meta + uses: docker/metadata-action@v3 + with: + images: ${{ secrets.DOCKERHUB_REPO}}/postgis + tags: | + type=semver,pattern=\d-\d.\d + type=ref,event=branch + type=ref,event=pr + + - name: Build image for testing + id: docker_build_testing_image + uses: docker/build-push-action@v2 + with: + context: . + file: Dockerfile + push: true + tags: | + ${{ steps.docker_meta.outputs.tags }}-${{ matrix.postgresMajorVersion }}-${{ matrix.postgisMajorVersion }}.${{ matrix.postgisMinorRelease }} + build-args: | + DISTRO=${{ matrix.distro }} + IMAGE_VERSION=${{ matrix.imageVersion }} + IMAGE_VARIANT=${{ matrix.imageVariant }} + LANGS=en_US.UTF-8,id_ID.UTF-8 + GENERATE_ALL_LOCALE=0 + POSTGRES_MAJOR_VERSION=${{ matrix.postgresMajorVersion }} + POSTGIS_MAJOR_VERSION=${{ matrix.postgisMajorVersion }} + POSTGIS_MINOR_VERSION=${{ matrix.postgresMinorVersion }} + cache-from: | + type=gha,scope=test + type=gha,scope=prod + type=gha,scope=base + cache-to: type=gha,scope=test + target: postgis-test diff --git a/.github/workflows/deploy-image.yaml b/.github/workflows/deploy-image.yaml new file mode 100644 index 00000000..a7a8c7ce --- /dev/null +++ b/.github/workflows/deploy-image.yaml @@ -0,0 +1,114 @@ +name: deploy-image +on: + workflow_dispatch: +# inputs: +# distro: +# description: Base image distro +# required: true +# default: debian +# imageVersion: +# description: Base distro image version/release +# required: true +# default: bullseye +# imageVariant: +# description: Base image variant +# required: true +# default: slim + workflow_run: + workflows: + - build-latest + branches: + - 13.0 + types: + - completed +jobs: + deploy-image: + runs-on: ubuntu-latest + env: + latest-ref: refs/heads/develop + strategy: + matrix: + postgresMajorVersion: + - 13 + postgisMajorVersion: + - 3 + postgisMinorRelease: + - 1 + include: + - distro: debian + imageVersion: bullseye + imageVariant: slim + steps: + - uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: Get Current Date + id: current_date + shell: python + run: | + import datetime + now = datetime.datetime.utcnow() + print(f'::set-output name=formatted::{now:%Y.%m.%d}') + + - name: Build base image + id: docker_build_base + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64,linux/arm64 + file: Dockerfile + push: true + tags: | + ${{ secrets.DOCKERHUB_REPO }}/postgis:base + ${{ secrets.DOCKERHUB_REPO }}/postgis:base-${{ matrix.distro }}-${{ matrix.imageVersion }}-${{ matrix.imageVariant }} + build-args: | + DISTRO=${{ matrix.distro }} + IMAGE_VERSION=${{ matrix.imageVersion }} + IMAGE_VARIANT=${{ matrix.imageVariant }} + GENERATE_ALL_LOCALE=1 + POSTGRES_MAJOR_VERSION=${{ matrix.postgresMajorVersion }} + POSTGIS_MAJOR_VERSION=${{ matrix.postgisMajorVersion }} + POSTGIS_MINOR_VERSION=${{ matrix.postgresMinorVersion }} + cache-from: | + type=gha,scope=test + type=gha,scope=prod + type=gha,scope=base + cache-to: type=gha,scope=base + target: postgis-base + + - name: Build prod image + id: docker_build_prod + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64,linux/arm64 + file: Dockerfile + push: true + tags: | + ${{ secrets.DOCKERHUB_REPO }}/postgis:${{ matrix.postgresMajorVersion }} + ${{ secrets.DOCKERHUB_REPO }}/postgis:${{ matrix.postgresMajorVersion }}-${{ matrix.postgisMajorVersion }} + ${{ secrets.DOCKERHUB_REPO }}/postgis:${{ matrix.postgresMajorVersion }}-${{ matrix.postgisMajorVersion }}.${{ matrix.postgisMinorRelease }} + ${{ secrets.DOCKERHUB_REPO }}/postgis:${{ matrix.postgresMajorVersion }}-${{ matrix.postgisMajorVersion }}.${{ matrix.postgisMinorRelease }}--v${{ steps.current_date.outputs.formatted }} + build-args: | + DISTRO=${{ matrix.distro }} + IMAGE_VERSION=${{ matrix.imageVersion }} + IMAGE_VARIANT=${{ matrix.imageVariant }} + GENERATE_ALL_LOCALE=1 + POSTGRES_MAJOR_VERSION=${{ matrix.postgresMajorVersion }} + POSTGIS_MAJOR_VERSION=${{ matrix.postgisMajorVersion }} + POSTGIS_MINOR_VERSION=${{ matrix.postgresMinorVersion }} + cache-from: | + type=gha,scope=test + type=gha,scope=prod + type=gha,scope=base + cache-to: type=gha,scope=prod + target: postgis-prod diff --git a/.gitignore b/.gitignore index 05e944f6..43b946cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,12 @@ .idea +.vscode *.*~ */replication/pg-* */replication/docker-compose.override.yml .DS_Store .python-version venv +.venv __pycache__ + +.env diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index aad46563..00000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -sudo: required - -language: python - -services: - - docker - -python: - - '3.7' - -env: - - SCENARIO=datadir_init - - SCENARIO=replications - - SCENARIO=collations - - SCENARIO=extensions - - SCENARIO=logical_replication - -before_script: - - ./build-test.sh - -script: - - pushd scenario_tests/${SCENARIO} - - ./test.sh - - popd diff --git a/Dockerfile b/Dockerfile index eb390500..4f0c0d74 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,83 @@ -#--------- Generic stuff all our Dockerfiles should start with so we get caching ------------ +############################################################################## +# Base stage # +############################################################################## ARG DISTRO=debian -ARG IMAGE_VERSION=buster +ARG IMAGE_VERSION=bullseye ARG IMAGE_VARIANT=slim -FROM kartoza/postgis:$DISTRO-$IMAGE_VERSION-$IMAGE_VARIANT -MAINTAINER Tim Sutton +FROM $DISTRO:$IMAGE_VERSION-$IMAGE_VARIANT AS postgis-base +LABEL maintainer="Tim Sutton" + +# Reset ARG for version +ARG IMAGE_VERSION + +RUN apt-get -qq update --fix-missing && apt-get -qq --yes upgrade + +RUN set -eux \ + && export DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get -y --no-install-recommends install \ + locales gnupg2 wget ca-certificates rpl pwgen software-properties-common iputils-ping \ + apt-transport-https curl gettext freetds-dev freetds-bin git dos2unix openvpn \ + && dpkg-divert --local --rename --add /sbin/initctl + +RUN apt-get -y update; apt-get -y install build-essential autoconf libxml2-dev zlib1g-dev netcat gdal-bin \ + figlet toilet + + + +# Generating locales takes a long time. Utilize caching by runnig it by itself +# early in the build process. + +# Generate all locale only on deployment mode build +# Set to empty string to generate only default locale +ARG GENERATE_ALL_LOCALE=1 +ARG LANGS="en_US.UTF-8,id_ID.UTF-8" +ARG LANG=en_US.UTF-8 +ENV LANG=en_US.UTF-8 \ + LANGUAGE=en_US:en \ + LC_ALL=en_US.UTF-8 + +COPY ./base_build/scripts/locale.gen /etc/all.locale.gen +COPY ./base_build/scripts/locale-filter.sh /etc/locale-filter.sh +RUN if [ -z "${GENERATE_ALL_LOCALE}" ] || [ $GENERATE_ALL_LOCALE -eq 0 ]; \ + then \ + cat /etc/all.locale.gen | grep "${LANG}" > /etc/locale.gen; \ + /bin/bash /etc/locale-filter.sh; \ + else \ + cp -f /etc/all.locale.gen /etc/locale.gen; \ + fi; \ + set -eux \ + && /usr/sbin/locale-gen + +RUN update-locale ${LANG} + +# Cleanup resources +RUN apt-get -y --purge autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + + +############################################################################## +# Production Stage # +############################################################################## +FROM postgis-base AS postgis-prod + # Reset ARG for version ARG IMAGE_VERSION ARG POSTGRES_MAJOR_VERSION=13 -ARG POSTGIS_MAJOR=3 +ARG POSTGIS_MAJOR_VERSION=3 +ARG POSTGIS_MINOR_RELEASE=1 +ARG TIMESCALE_VERSION=2 RUN set -eux \ && export DEBIAN_FRONTEND=noninteractive \ - && apt-get upgrade;apt-get update \ + && apt-get update \ && sh -c "echo \"deb http://apt.postgresql.org/pub/repos/apt/ ${IMAGE_VERSION}-pgdg main\" > /etc/apt/sources.list.d/pgdg.list" \ && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | apt-key add - \ + && sh -c "echo \"deb [signed-by=/usr/share/keyrings/timescale.keyring] https://packagecloud.io/timescale/timescaledb/debian/ ${IMAGE_VERSION} main\" > /etc/apt/sources.list.d/timescaledb.list" \ + && wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | gpg --dearmor -o /usr/share/keyrings/timescale.keyring \ && apt-get -y --purge autoremove \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ @@ -32,15 +94,19 @@ RUN set -eux \ && apt-get update \ && apt-get -y --no-install-recommends install postgresql-client-${POSTGRES_MAJOR_VERSION} \ postgresql-common postgresql-${POSTGRES_MAJOR_VERSION} \ - postgresql-${POSTGRES_MAJOR_VERSION}-postgis-${POSTGIS_MAJOR} \ + postgresql-${POSTGRES_MAJOR_VERSION}-postgis-${POSTGIS_MAJOR_VERSION} \ netcat postgresql-${POSTGRES_MAJOR_VERSION}-ogr-fdw \ - postgresql-${POSTGRES_MAJOR_VERSION}-postgis-${POSTGIS_MAJOR}-scripts \ + postgresql-${POSTGRES_MAJOR_VERSION}-postgis-${POSTGIS_MAJOR_VERSION}-scripts \ postgresql-plpython3-${POSTGRES_MAJOR_VERSION} postgresql-${POSTGRES_MAJOR_VERSION}-pgrouting \ - postgresql-server-dev-${POSTGRES_MAJOR_VERSION} postgresql-${POSTGRES_MAJOR_VERSION}-cron - + postgresql-server-dev-${POSTGRES_MAJOR_VERSION} postgresql-${POSTGRES_MAJOR_VERSION}-cron \ + timescaledb-${TIMESCALE_VERSION}-postgresql-${POSTGRES_MAJOR_VERSION} timescaledb-tools -RUN echo $POSTGRES_MAJOR_VERSION >/tmp/pg_version.txt +RUN echo $POSTGRES_MAJOR_VERSION >/tmp/pg_version.txt +RUN echo $POSTGIS_MAJOR_VERSION >/tmp/pg_major_version.txt +RUN echo $POSTGIS_MINOR_RELEASE >/tmp/pg_minor_version.txt +ENV \ + PATH="$PATH:/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin" # Compile pointcloud extension RUN wget -O- https://github.com/pgpointcloud/pointcloud/archive/master.tar.gz | tar xz && \ @@ -57,15 +123,50 @@ RUN apt-get -y --purge autoremove \ EXPOSE 5432 # Copy scripts -ADD scripts /scripts +ADD ./scripts /scripts WORKDIR /scripts RUN chmod +x *.sh # Run any additional tasks here that are too tedious to put in # this dockerfile directly. + +# Installez les dependances requises pour l'extension tds_fdw +RUN git clone https://github.com/tds-fdw/tds_fdw.git \ + && cd tds_fdw \ + && make && make install \ + && rm -rf /var/lib/apt/lists/* + +# Copiez le fichier d'extension tds_fdw dans le conteneur +#COPY tds_fdw.control /usr/share/postgresql/${POSTGRES_MAJOR_VERSION}/extension/ + +#COPY des fichiers de configuration VPN + +COPY vpn.conf /etc/openvpn/vpn.conf +COPY userpass.txt /etc/openvpn/userpass.txt + +# Convertir tous les fichiers scripts en .lf +RUN find /scripts -type f -name "*.sh" -exec dos2unix {} + + RUN set -eux \ && /scripts/setup.sh - +RUN echo 'figlet -t "Kartoza Docker PostGIS"' >> ~/.bashrc VOLUME /var/lib/postgresql +ENTRYPOINT /scripts/docker-entrypoint.sh + + +############################################################################## +# Testing Stage # +############################################################################## +FROM postgis-prod AS postgis-test + +COPY ./scenario_tests/utils/requirements.txt /lib/utils/requirements.txt + +RUN set -eux \ + && export DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get -y --no-install-recommends install python3-pip \ + && apt-get -y --purge autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* -ENTRYPOINT /scripts/docker-entrypoint.sh \ No newline at end of file +RUN pip3 install -r /lib/utils/requirements.txt diff --git a/Dockerfile.test b/Dockerfile.test deleted file mode 100644 index c897705a..00000000 --- a/Dockerfile.test +++ /dev/null @@ -1,16 +0,0 @@ -#--------- Generic stuff all our Dockerfiles should start with so we get caching ------------ -FROM kartoza/postgis:manual-build - -# For testing - -COPY scenario_tests/utils/requirements.txt /lib/utils/requirements.txt - -RUN set -eux \ - && export DEBIAN_FRONTEND=noninteractive \ - && apt-get update \ - && apt-get -y --no-install-recommends install python3-pip \ - && apt-get -y --purge autoremove \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -RUN pip3 install -r /lib/utils/requirements.txt diff --git a/README.md b/README.md index 9edac61f..17cf2900 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -[![Build Status](https://travis-ci.org/kartoza/docker-postgis.svg?branch=develop)](https://travis-ci.org/kartoza/docker-postgis) +[![Scenario Tests](https://github.com/kartoza/docker-postgis/actions/workflows/build-latest.yaml/badge.svg?branch=develop&event=push)](https://github.com/kartoza/docker-postgis/actions/workflows/build-latest.yaml) +[![deploy-image](https://github.com/kartoza/docker-postgis/actions/workflows/deploy-image.yaml/badge.svg)](https://github.com/kartoza/docker-postgis/actions/workflows/deploy-image.yaml) # docker-postgis @@ -9,15 +10,17 @@ Visit our page on the docker hub at: https://hub.docker.com/r/kartoza/postgis/ There are a number of other docker postgis containers out there. This one differentiates itself by: -* provides ssl support out of the box +* provides ssl support out of the box and enforces ssl client connections * connections are restricted to the docker subnet * a default database 'gis' is created for you so you can use this container 'out of the box' when it runs with e.g. QGIS -* replication support included +* Streaming replication and logical replication support included (turned off by default) * Ability to create multiple database when you spin the database. -* Enable multiple extensions in the database when setting it up -* Gdal drivers automatically registered for pg raster -* Support for out-of-db rasters +* Ability to create multiple schemas when spinning the database. +* Enable multiple extensions in the database when setting it up. +* Gdal drivers automatically registered for pg raster. +* Support for out-of-db rasters. + We will work to add more security features to this container in the future with the aim of making a PostGIS image that is ready to be used in a production @@ -51,39 +54,37 @@ There are various ways to get the image onto your system: The preferred way (but using most bandwidth for the initial image) is to get our docker trusted build like this: -``` +```shell docker pull kartoza/postgis:image_version ``` - - ## Building the image -To build the image yourself without apt-cacher (also consumes more bandwidth -since deb packages need to be fetched each time you build) do: +To build the image yourself do: -``` +```shell docker build -t kartoza/postgis git://github.com/kartoza/docker-postgis ``` -Alternatively clone the repository and build against any preferred branch +Alternatively clone the repository and build against any preferred branch -``` +```shell git clone git://github.com/kartoza/docker-postgis git checkout branch_name ``` Then do: -``` +```shell docker build -t kartoza/postgis . ``` -Or +Or build against a specific PostgreSQL version -``` +```shell docker build --build-arg POSTGRES_MAJOR_VERSION=13 --build-arg POSTGIS_MAJOR=3 -t kartoza/postgis:POSTGRES_MAJOR_VERSION . ``` + #### Alternative base distributions builds There are build args for `DISTRO` (=debian), `IMAGE_VERSION` (=buster) @@ -91,28 +92,35 @@ and `IMAGE_VARIANT` (=slim) which can be used to control the base image used (but it still needs to be Debian based and have PostgreSQL official apt repo). For example making Ubuntu 20.04 based build (for better arm64 support) -First build the base image using the branch `postgres-base` following instructions from [Kartoza base image builds](https://github.com/kartoza/docker-postgis/tree/postgres-base#alternative-base-distributions-builds) - -And then build the `PostGIS Image` using +Edit the `.env` file to change the build arguments +```dotenv +DISTRO=ubuntu +IMAGE_VERSION=focal +IMAGE_VARIANT="" ``` -docker build --build-arg DISTRO=ubuntu --build-arg IMAGE_VERSION=focal --build-arg IMAGE_VARIANT="" -t kartoza/postgis . + +Then run the script + +```shell +./build.sh ``` #### Locales -By default, the image build will include **all** `locales` to cover any value for `locale` settings such as `DEFAULT_COLLATION`, `DEFAULT_CTYPE` or `DEFAULT_ENCODING`. +By default, the image build will include **all** `locales` to cover any value for `locale` settings such as `DEFAULT_COLLATION`, `DEFAULT_CTYPE` or `DEFAULT_ENCODING`. + +You can use the build argument: `GENERATE_ALL_LOCALE=0` -You can safely delete all `locales` except for the ones you need in `scripts/locale.gen`. This will speed up the build considerably. +This will build with the default locate and speed up the build considerably. -You can also run the container using the environment variables. ### Environment variables #### Cluster Initializations -With minimum setup, our image will use initial cluster located in the +With a minimum setup, our image will use an initial cluster located in the `DATADIR` environment variable. If you want to use persistence, mount these -location into your volume/host. By default, `DATADIR` will point to `/var/lib/postgresql/{major-version}`. +locations into your volume/host. By default, `DATADIR` will point to `/var/lib/postgresql/{major-version}`. You can instead mount the parent location like this: * `-v data-volume:/var/lib/postgresql` @@ -121,36 +129,39 @@ This default cluster will be initialized with default locale settings `C.UTF-8`. If, for instance, you want to create a new cluster with your own settings (not using the default cluster). You need to specify different empty directory, like this -```shell script +```shell -v data-volume:/opt/postgres/data \ -e DATADIR:/opt/postgres/data \ -e DEFAULT_ENCODING="UTF8" \ -e DEFAULT_COLLATION="id_ID.utf8" \ -e DEFAULT_CTYPE="id_ID.utf8" \ --e --auth="md5" \ --e INITDB_EXTRA_ARGS="" +-e PASSWORD_AUTHENTICATION="md5" \ +-e INITDB_EXTRA_ARGS="" \ +-v pgwal-volume:/opt/postgres/pg_wal \ +-e POSTGRES_INITDB_WALDIR=/opt/postgres/pg_wal ``` The containers will use above parameters to initialize a new db cluster in the specified directory. If the directory is not empty, then initialization parameter will be ignored. -These are some initialization parameter that will only be used to initialize new cluster. -If the container uses existing cluster, it will be ignored (for example, when the container restarts). +These are some initialization parameters that will only be used to initialize a new cluster. +If the container uses an existing cluster, it is ignored (for example, when the container restarts). * `DEFAULT_ENCODING`: cluster encoding * `DEFAULT_COLLATION`: cluster collation * `DEFAULT_CTYPE`: cluster ctype * `WAL_SEGSIZE`: WAL segsize option -* `--auth` : PASSWORD AUTHENTICATION +* `PASSWORD_AUTHENTICATION` : PASSWORD AUTHENTICATION * `INITDB_EXTRA_ARGS`: extra parameter that will be passed down to `initdb` command +* `POSTGRES_INITDB_WALDIR`: parameter to tell postgres about the initial waldir location. Note that you must always mount persistent volume to this location. Postgres will expect that the directory will always be available, even though it doesn't need the environment variable anymore. If you didn't persist this location, postgres will not be able to find the `pg_wal` directory and consider the instance to be broken. In addition to that, we have another parameter: `RECREATE_DATADIR` that can be used to force database reinitializations. If this parameter is specified as `TRUE` it will act as explicit consent to delete `DATADIR` and create new db cluster. -* `RECREATE_DATADIR`: Force database reinitializations in the location `DATADIR` +* `RECREATE_DATADIR`: Force database reinitialization in the location `DATADIR` -If you used `RECREATE_DATADIR` and successfully created new cluster. Remember +If you used `RECREATE_DATADIR` and successfully created a new cluster. Remember that you should remove this parameter afterwards. Because, if it was not omitted, it will always recreate new db cluster after every container restarts. @@ -170,32 +181,36 @@ or If you use default `DATADIR` location. -If you need to setup a database cluster with other encoding parameters you need +If you need to set up a database cluster with other encoding parameters you need to pass the environment variables when you initialize the cluster. -* -e DEFAULT_ENCODING="UTF8" -* -e DEFAULT_COLLATION="en_US.UTF-8" -* -e DEFAULT_CTYPE="en_US.UTF-8" +* `-e DEFAULT_ENCODING="UTF8"` +* `-e DEFAULT_COLLATION="en_US.UTF-8"` +* `-e DEFAULT_CTYPE="en_US.UTF-8"` Initializing a new cluster can be done by using different `DATADIR` location and mounting an empty volume. Or use parameter `RECREATE_DATADIR` to forcefully delete the current cluster and create a new one. Make sure to remove parameter `RECREATE_DATADIR` after creating the cluster. +See [the postgres documentation about encoding](https://www.postgresql.org/docs/11/multibyte.html) for more information. #### Basic configuration You can use the following environment variables to pass a -user name, password and/or default database name(or multiple databases comma separated). +username, password and/or default database name(or multiple databases comma separated). * `-e POSTGRES_USER=` * `-e POSTGRES_PASS=` +**NB** You should use a strong passwords. If you are using docker-compose make sure +docker can interpolate the password. Example using a password with a `$` you will +need to escape it ie `$$` * `-e POSTGRES_DBNAME=` * `-e POSTGRES_MULTIPLE_EXTENSIONS=postgis,hstore,postgis_topology,postgis_raster,pgrouting` You can pass as many extensions as you need. * `-e SHARED_PRELOAD_LIBRARIES='pg_cron'` -Some extensions need to be registered in the postgresql.conf +Some extensions need to be registered in the `postgresql.conf` as shared_preload_libraries. pg_cron should always be added because the extension is installed with the image. * `-e SSL_CERT_FILE=/your/own/ssl_cert_file.pem` @@ -207,7 +222,16 @@ the extension is installed with the image. * `-e POSTGRES_TEMPLATE_EXTENSIONS=true` - ` Specifies whether extensions will also be installed in template1 database.` +Specifies whether extensions will also be installed in template1 database. + +### Schema Initialisation + +* `-e SCHEMA_NAME=` +You can pass a comma separated value of schema names which will be created when the + database initialises. The default behaviour is to create the schema in the first + database specified in the environment variable `POSTGRES_DBNAME`. If you need to + create matching schemas in all the databases that will be created you use + the environment variable `ALL_DATABASES=TRUE` #### Configures archive mode @@ -223,6 +247,7 @@ When `ARCHIVE_MODE` is changed to `on`, the archiving command will copy WAL file * `-e RESTORE_COMMAND='cp /opt/archivedir/%f "%p"'` #### Configure WAL level + * `-e WAL_LEVEL=replica` [More info](https://www.postgresql.org/docs/12/runtime-config-wal.html) @@ -233,22 +258,29 @@ Maximum size to let the WAL grow to between automatic WAL checkpoints. * `-e MAINTAINANCE_WORK_MEM=128MB` #### Configure networking -You can open up the PG port by using the following environment variable. By default + +You can open up the PG port by using the following environment variable. By default, the container will allow connections only from the docker private subnet. * `-e ALLOW_IP_RANGE=<0.0.0.0/0> By default` -Postgres conf is setup to listen to all connections and if a user needs to restrict which IP address +Postgres conf is set up to listen to all connections and if a user needs to restrict which IP address PostgreSQL listens to you can define it with the following environment variable. The default is set to listen to all connections. * `-e IP_LIST=<*>` #### Additional configuration -You can also define any other configuration to add to `postgres.conf`, separated by '\n' e.g.: +You can also define any other configuration to add to `extra.conf`, separated by '\n' e.g.: * `-e EXTRA_CONF="log_destination = 'stderr'\nlogging_collector = on"` +You can alternatively mount an extra config file into the setting's folder i.e + +```shell +docker run --name "postgis" -v /data/extra.conf:/settings/extra.conf -p 25432:5432 -d -t kartoza/postgis +``` + If you want to reinitialize the data directory from scratch, you need to do: 1. Do backup, move data, etc. Any preparations before deleting your data directory. @@ -261,11 +293,12 @@ To avoid passing sensitive information in environment variables, `_FILE` can be some of the variables to read from files present in the container. This is particularly useful in conjunction with Docker secrets, as passwords can be loaded from `/run/secrets/` e.g.: -* -e POSTGRES_PASS_FILE=/run/secrets/ +* `-e POSTGRES_PASS_FILE=/run/secrets/` For more information see [https://docs.docker.com/engine/swarm/secrets/](https://docs.docker.com/engine/swarm/secrets/). -Currently, `POSTGRES_PASS`, `POSTGRES_USER` and `POSTGRES_DB` are supported. +Currently, `POSTGRES_PASS`, `POSTGRES_USER`, `POSTGRES_DB`, `SSL_CERT_FILE`, +`SSL_KEY_FILE`, `SSL_CA_FILE` are supported. ## Running the container @@ -274,13 +307,17 @@ Currently, `POSTGRES_PASS`, `POSTGRES_USER` and `POSTGRES_DB` are supported. To create a running container do: -``` +```shell docker run --name "postgis" -p 25432:5432 -d -t kartoza/postgis ``` +**Note** If you do not pass the env variable `POSTGRES_PASS` a random password +will be generated and will be visible from the logs or within the container in +`/tmp/PGPASSWORD.txt` + ## Convenience docker-compose.yml -For convenience we have provided a ``docker-compose.yml`` that will run a +For convenience, we provide a ``docker-compose.yml`` that will run a copy of the database image and also our related database backup image (see [https://github.com/kartoza/docker-pg-backup](https://github.com/kartoza/docker-pg-backup)). @@ -289,7 +326,7 @@ potential conflicts with any local database instance you may have). Example usage: -``` +```shell docker-compose up -d ``` @@ -302,7 +339,7 @@ Connect with psql (make sure you first install postgresql client tools on your host / client): -``` +```shell psql -h localhost -U docker -p 25432 -l ``` @@ -312,36 +349,34 @@ You can then go on to use any normal postgresql commands against the container. Under ubuntu 16.04 the postgresql client can be installed like this: -``` +```shell sudo apt-get install postgresql-client-12 ``` ## Running SQL scripts on container startup. - In some instances users want to run some SQL scripts to populate the -database. Since the environment variable POSTGRES_DB allows +database. The environment variable POSTGRES_DB allows us to specify multiple database that can be created on startup. When running scripts they will only be executed against the first database ie POSTGRES_DB=gis,data,sample -The SQL script will be executed against the gis database. +The SQL script will be executed against the `gis` database. Additionally, a lock file is generated in +`/docker-entrypoint-initdb.d`, which will prevent the scripts from getting executed after the first +container startup. Provide `IGNORE_INIT_HOOK_LOCKFILE=true` to execute the scripts on _every_ container start. -Currently you can pass `.sql` , `.sql.gz` and `.sh` files as mounted volumes. - -``` +Currently, you can pass `.sql`, `.sql.gz` and `.sh` files as mounted volumes. -docker run -d -v ./setup-db.sql:/docker-entrypoint-initdb.d/setup-db.sql kartoza/postgis` +```shell +docker run -d -v `pwd`/setup-db.sql:/docker-entrypoint-initdb.d/setup-db.sql kartoza/postgis ``` - ## Storing data on the host rather than the container. - Docker volumes can be used to persist your data. -``` +```shell mkdir -p ~/postgres_data -docker run -d -v $HOME/postgres_data:/var/lib/postgresql kartoza/postgis` +docker run -d -v $HOME/postgres_data:/var/lib/postgresql kartoza/postgis ``` You need to ensure the ``postgres_data`` directory has sufficient permissions @@ -349,45 +384,119 @@ for the docker process to read / write it. ## Postgres SSL setup -By default the image is delivered with an unsigned SSL certificate. This helps to have an -encrypted connection to clients and avoid eavesdropping but does not help to mitigate +There are three modalities in which you can work with SSL: + + 1. Optional: using the shipped snakeoil certificates + 2. Forced SSL: forced using the shipped snakeoil certificates + 3. Forced SSL with Certificate Exchange: using SSL certificates signed by a certificate authority + + +By default, the image is delivered with an unsigned SSL certificate. +This helps to have an encrypted connection to clients and avoid eavesdropping but does not help to mitigate man in the middle (MITM) attacks. You need to provide your own, signed private key to avoid this kind of attacks (and make sure clients connect with verify-ca or verify-full sslmode). -The following is an example Dockerfile that sets up a container with custom ssl private key and certificate: +Although SSL is enabled by default, connection to PostgreSQL with other clients +i.e (PSQL or QGIS) still doesn't enforce SSL encryption. To force SSL connection between clients you +need to use the environment variable +```shell +FORCE_SSL=TRUE ``` -FROM kartoza/postgis:11.0-2.5 -ADD ssl_cert.pem /etc/ssl/certs/ssl_cert.pem -ADD localhost_ssl_key.pem /etc/ssl/private/ssl_key.pem +The following example sets up a container with custom ssl private key and certificate: -RUN chmod 400 /etc/ssl/private/ssl_key.pem + +```shell +docker run -p 25432:5432 -e FORCE_SSL=TRUE -e SSL_DIR="/etc/ssl_certificates" -e SSL_CERT_FILE='/etc/ssl_certificates/fullchain.pem' -e SSL_KEY_FILE='/etc/ssl_certificates/privkey.pem' -e SSL_CA_FILE='/etc/ssl_certificates/root.crt' -v /tmp/postgres/letsencrypt:/etc/ssl_certificates --name ssl -d kartoza/postgis:13-3.1 ``` -And a docker-compose.yml to initialize with this configuration: +The environment variable `SSL_DIR` allows a user to specify the location +where custom SSL certificates will be located. The environment variable currently +defaults to `SSL_DIR=/ssl_certificates` + +See [the postgres documentation about SSL](https://www.postgresql.org/docs/11/libpq-ssl.html#LIBQ-SSL-CERTIFICATES) for more information. + +### Forced SSL: forced using the shipped snakeoil certificates + +If you are using the default certificates provided by the image when connecting +to the database you will need to set `SSL Mode` to any value besides +`verify-full` or `verify-ca` +The pg_hba.con will have entries like: + +```shell +hostssl all all 0.0.0.0/0 scram-sha-256 clientcert=0 ``` -services: - postgres: - build: - dockerfile: Dockerfile - context: ssl_secured_docker - environment: - - SSL_CERT_FILE=/etc/ssl/certs/ssl_cert.pem - - SSL_KEY_FILE=/etc/ssl/private/ssl_key.pem + +where `PASSWORD_AUTHENTICATION=scram-sha-256` and `ALLOW_IP_RANGE=0.0.0.0/0` + + +### Forced SSL with Certificate Exchange: using SSL certificates signed by a certificate authority + +When setting up the database you need to define the following environment variables. + +SSL_CERT_FILE: + +SSL_KEY_FILE: + +SSL_CA_FILE: + +Example: + +```shell +docker run -p 5432:5432 -e FORCE_SSL=TRUE -e SSL_CERT_FILE='/ssl_certificates/fullchain.pem' -e SSL_KEY_FILE='/ssl_certificates/privkey.pem' -e SSL_CA_FILE='/ssl_certificates/root.crt' --name ssl -d kartoza/postgis:13-3.1 ``` -See [the postgres documentation about SSL](https://www.postgresql.org/docs/11/libpq-ssl.html#LIBQ-SSL-CERTIFICATES) for more information. +On the host machine where you need to connect to the database you also +need to copy the `SSL_CA_FILE` file to the location `/home/$user/.postgresql/root.crt` +or define an environment variable pointing to location of the `SSL_CA_FILE` +example: `PGSSLROOTCERT=/etc/letsencrypt/root.crt` -See [the postgres documentation about encoding](https://www.postgresql.org/docs/11/multibyte.html) for more information. +The `pg_hba.conf` will have entries like: + +``` +hostssl all all 0.0.0.0/0 cert +``` + +where `ALLOW_IP_RANGE=0.0.0.0/0` + +#### SSL connection inside the docker container using openssl certificates + + +Generate the certificates inside the container + +```shell +CERT_DIR=/ssl_certificates +mkdir $CERT_DIR +openssl req -x509 -newkey rsa:4096 -keyout ${CERT_DIR}/privkey.pem -out \ + ${CERT_DIR}/fullchain.pem -days 3650 -nodes -sha256 -subj '/CN=localhost' + +cp $CERT_DIR/fullchain.pem $CERT_DIR/root.crt +chmod -R 0700 ${CERT_DIR} +chown -R postgres ${CERT_DIR} +``` +Set up your ssl config to point to the new location + +``` +ssl = true +ssl_cert_file = '/ssl_certificates/fullchain.pem' +ssl_key_file = '/ssl_certificates/privkey.pem' +ssl_ca_file = '/ssl_certificates/root.crt' +``` + +Then connect to the database using the psql command: + +```shell +psql "dbname=gis port=5432 user=docker host=localhost sslmode=verify-full sslcert=/etc/letsencrypt/fullchain.pem sslkey=/etc/letsencrypt/privkey.pem sslrootcert=/etc/letsencrypt/root.crt" +``` ## Postgres Replication Setup -The image supports replication out of the box. By default replication is turned off. +The image supports replication out of the box. By default, replication is turned off. The two mains replication methods allowed are * Streaming replication * Logical replication @@ -401,10 +510,13 @@ with the green fill is accessed from the replicant database. When edits to the m layer are saved, they are automatically propagated to the replicant. Note also that the replicant is read-only. -``` +```shell docker run --name "streaming-replication" -e REPLICATION=true -e WAL_LEVEL='replica' -d -p 25432:5432 kartoza/postgis:13.0 ``` +**Note** If you do not pass the env variable `REPLICATION_PASS` a random password +will be generated and will be visible from the logs or within the container in +`/tmp/REPLPASSWORD.txt` ![qgis](https://user-images.githubusercontent.com/178003/37755610-dd3b774a-2dae-11e8-9fa1-4877e2034675.gif) @@ -413,28 +525,30 @@ categorize an instance of the container as `master` or `replicant`. A `master` instance means that a particular container has a role as a single point of database write. A `replicant` instance means that a particular container will mirror database content from a designated master. This replication scheme allows -us to sync databases. However a `replicant` is only for read-only transaction, thus +us to sync databases. However, a `replicant` is only for read-only transaction, thus we can't write new data to it. The whole database cluster will be replicated. #### Database permissions + Since we are using a role ${REPLICATION_USER}, we need to ensure that it has access to all the tables in a particular schema. So if a user adds another schema called `data` to the database `gis` he also has to update the permission for the user with the following SQL assuming the ${REPLICATION_USER} is called replicator - ALTER DEFAULT PRIVILEGES IN SCHEMA data GRANT SELECT ON TABLES TO replicator; - +```sql +ALTER DEFAULT PRIVILEGES IN SCHEMA data GRANT SELECT ON TABLES TO replicator; +``` -**NB** You need to setup a strong password for replication otherwise the +**NB** You need to set up a strong password for replication otherwise the default password for ${REPLICATION_USER} will default to `replicator` To experiment with the replication abilities, you can see a [docker-compose.yml](sample/replication/docker-compose.yml) sample. There are several environment variables that you can set, such as: Master settings: -- **ALLOW_IP_RANGE**: A pg_hba.conf domain format which will allow specified host(s) +- **ALLOW_IP_RANGE**: A `pg_hba.conf` domain format which will allow specified host(s) to connect into the container. This is needed to allow the `slave` to connect - into `master`, so specifically this settings should allow `slave` address. It is also needed to allow clients on other hosts to connect to either the slave or the master. + into `master`, so specifically these settings should allow `slave` address. It is also needed to allow clients on other hosts to connect to either the slave or the master. - **REPLICATION_USER** User to initiate streaming replication - **REPLICATION_PASS** Password for a user with streaming replication role @@ -461,26 +575,26 @@ To run the sample replication, follow these instructions: Do a manual image build by executing the `build.sh` script -``` +```shell ./build.sh ``` Go into the `sample/replication` directory and experiment with the following Make command to run both master and slave services. -``` +```shell make up ``` -To shutdown services, execute: +To shut down services, execute: -``` +```shell make down ``` To view logs for master and slave respectively, use the following command: -``` +```shell make master-log make slave-log ``` @@ -494,7 +608,7 @@ connecting using POSTGRES_USER and POSTGRES_PASS credentials using exposed port. In the sample, the master database was exposed on port 7777. Or you can do it via command line, by entering the shell: -``` +```shell make master-shell ``` @@ -505,7 +619,7 @@ slave database. You can, again, use database management tools using connection credentials, hostname, and ports for replicant. Or you can do it via command line, by entering the shell: -``` +```shell make slave-shell ``` @@ -533,26 +647,38 @@ However, you should note that this option doesn't mean anything if you didn't persist your database volume. Because if it is not persisted, then it will be lost on restart because docker will recreate the container. -### Logical replication +### Logical replication + To activate the following you need to use the environment variable `WAL_LEVEL=logical` to get a running instance like -``` +```shell docker run --name "logical-replication" -e WAL_LEVEL=logical -d kartoza/postgis:13.0 ``` + For a detailed example see the docker-compose in the folder `sample/logical_replication`. +### Docker image versions + +All instructions mentioned in the README are valid for the latest running image. +Other docker images might have a few missing features than the ones in the +latest image. We mainly do not back port changes to current stable images that are being +used in production. However, if you feel that some changes included +in the latest tagged version of the image are essential for the previous image +you can cherry-pick the changes against that specific branch and we will +test and merge. ### Support If you require more substantial assistance from [kartoza](https://kartoza.com) (because our work and interaction on docker-postgis is pro bono), -please consider taking out a [Support Level Agreeement](https://kartoza.com/en/shop/product/support) +please consider taking out a [Support Level Agreeement](https://kartoza.com/en/shop/product/support) ## Credits -Tim Sutton (tim@kartoza.com) -Gavin Fleming (gavin@kartoza.com) -Rizky Maulana (rizky@kartoza.com) -Admire Nyakudya (admire@kartoza.com) -October 2020 \ No newline at end of file +- Tim Sutton (tim@kartoza.com) +- Gavin Fleming (gavin@kartoza.com) +- Rizky Maulana (rizky@kartoza.com) +- Admire Nyakudya (admire@kartoza.com) + +March 2021 diff --git a/base_build/README.md b/base_build/README.md new file mode 100644 index 00000000..9979565f --- /dev/null +++ b/base_build/README.md @@ -0,0 +1,44 @@ +[![Build Status](https://travis-ci.org/kartoza/docker-postgis.svg?branch=develop)](https://travis-ci.org/kartoza/docker-postgis) + +# docker-postgis + +A docker image that installs all the dependency for building `kartoza/postgis` image variants. + +Visit our page on the docker hub at: https://hub.docker.com/r/kartoza/postgis/ + + +#### Alternative base distributions builds + +There are build args for `DISTRO` (=debian), `IMAGE_VERSION` (=buster) +and `IMAGE_VARIANT` (=slim) which can be used to control the base image used +(but it still needs to be Debian based and have PostgreSQL official apt repo). + +For example making Ubuntu 20.04 based build (for better arm64 support) +First build the base image using the in the folder `base_build` using the +build script +following instructions from [Kartoza base image builds](https://github.com/kartoza/docker-postgis/tree/postgres-base#alternative-base-distributions-builds) + +Then build the `PostGIS base Image` using + +``` +docker build --build-arg DISTRO=ubuntu --build-arg IMAGE_VERSION=focal --build-arg IMAGE_VARIANT="" -t kartoza/postgis:$DISTRO-$IMAGE_VERSION-$IMAGE_VARIANT-base . +``` + +#### Locales + +By default, the image build will include **all** `locales` to cover any value for `locale` settings such as `DEFAULT_COLLATION`, `DEFAULT_CTYPE` or `DEFAULT_ENCODING`. + +You can safely delete all `locales` except for the ones you need in `scripts/locale.gen`. This will speed up the build considerably. + +### Support + +If you require more substantial assistance from [kartoza](https://kartoza.com) (because our work and interaction on docker-postgis is pro bono), +please consider taking out a [Support Level Agreeement](https://kartoza.com/en/shop/product/support) + +## Credits + +Tim Sutton (tim@kartoza.com) +Gavin Fleming (gavin@kartoza.com) +Rizky Maulana (rizky@kartoza.com) +Admire Nyakudya (admire@kartoza.com) +December 2020 diff --git a/base_build/scripts/locale-filter.sh b/base_build/scripts/locale-filter.sh new file mode 100644 index 00000000..8b37747b --- /dev/null +++ b/base_build/scripts/locale-filter.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +## Filter list of locales from a given filter args +## Parse into array +LANG_ARR=(${LANGS//,/ }) +echo "" > /etc/locale.gen +for i in "${LANG_ARR[@]}"; do + cat /etc/all.locale.gen | grep "$i" >> /etc/locale.gen +done diff --git a/base_build/scripts/locale.gen b/base_build/scripts/locale.gen new file mode 100644 index 00000000..39952867 --- /dev/null +++ b/base_build/scripts/locale.gen @@ -0,0 +1,484 @@ +# This file lists locales that you wish to have built. You can find a list +# of valid supported locales at /usr/share/i18n/SUPPORTED, and you can add +# user defined locales to /usr/local/share/i18n/SUPPORTED. If you change +# this file, you need to rerun locale-gen. + + +aa_DJ ISO-8859-1 +aa_DJ.UTF-8 UTF-8 +aa_ER UTF-8 +aa_ER@saaho UTF-8 +aa_ET UTF-8 +af_ZA ISO-8859-1 +af_ZA.UTF-8 UTF-8 +ak_GH UTF-8 +am_ET UTF-8 +an_ES ISO-8859-15 +an_ES.UTF-8 UTF-8 +anp_IN UTF-8 +ar_AE ISO-8859-6 +ar_AE.UTF-8 UTF-8 +ar_BH ISO-8859-6 +ar_BH.UTF-8 UTF-8 +ar_DZ ISO-8859-6 +ar_DZ.UTF-8 UTF-8 +ar_EG ISO-8859-6 +ar_EG.UTF-8 UTF-8 +ar_IN UTF-8 +ar_IQ ISO-8859-6 +ar_IQ.UTF-8 UTF-8 +ar_JO ISO-8859-6 +ar_JO.UTF-8 UTF-8 +ar_KW ISO-8859-6 +ar_KW.UTF-8 UTF-8 +ar_LB ISO-8859-6 +ar_LB.UTF-8 UTF-8 +ar_LY ISO-8859-6 +ar_LY.UTF-8 UTF-8 +ar_MA ISO-8859-6 +ar_MA.UTF-8 UTF-8 +ar_OM ISO-8859-6 +ar_OM.UTF-8 UTF-8 +ar_QA ISO-8859-6 +ar_QA.UTF-8 UTF-8 +ar_SA ISO-8859-6 +ar_SA.UTF-8 UTF-8 +ar_SD ISO-8859-6 +ar_SD.UTF-8 UTF-8 +ar_SS UTF-8 +ar_SY ISO-8859-6 +ar_SY.UTF-8 UTF-8 +ar_TN ISO-8859-6 +ar_TN.UTF-8 UTF-8 +ar_YE ISO-8859-6 +ar_YE.UTF-8 UTF-8 +as_IN UTF-8 +ast_ES ISO-8859-15 +ast_ES.UTF-8 UTF-8 +ayc_PE UTF-8 +az_AZ UTF-8 +be_BY CP1251 +be_BY.UTF-8 UTF-8 +be_BY@latin UTF-8 +bem_ZM UTF-8 +ber_DZ UTF-8 +ber_MA UTF-8 +bg_BG CP1251 +bg_BG.UTF-8 UTF-8 +bhb_IN.UTF-8 UTF-8 +bho_IN UTF-8 +bn_BD UTF-8 +bn_IN UTF-8 +bo_CN UTF-8 +bo_IN UTF-8 +br_FR ISO-8859-1 +br_FR.UTF-8 UTF-8 +br_FR@euro ISO-8859-15 +brx_IN UTF-8 +bs_BA ISO-8859-2 +bs_BA.UTF-8 UTF-8 +byn_ER UTF-8 +ca_AD ISO-8859-15 +ca_AD.UTF-8 UTF-8 +ca_ES ISO-8859-1 +ca_ES.UTF-8 UTF-8 +ca_ES.UTF-8@valencia UTF-8 +ca_ES@euro ISO-8859-15 +ca_ES@valencia ISO-8859-15 +ca_FR ISO-8859-15 +ca_FR.UTF-8 UTF-8 +ca_IT ISO-8859-15 +ca_IT.UTF-8 UTF-8 +ce_RU UTF-8 +chr_US UTF-8 +cmn_TW UTF-8 +crh_UA UTF-8 +cs_CZ ISO-8859-2 +cs_CZ.UTF-8 UTF-8 +csb_PL UTF-8 +cv_RU UTF-8 +cy_GB ISO-8859-14 +cy_GB.UTF-8 UTF-8 +da_DK ISO-8859-1 +da_DK.UTF-8 UTF-8 +de_AT ISO-8859-1 +de_AT.UTF-8 UTF-8 +de_AT@euro ISO-8859-15 +de_BE ISO-8859-1 +de_BE.UTF-8 UTF-8 +de_BE@euro ISO-8859-15 +de_CH ISO-8859-1 +de_CH.UTF-8 UTF-8 +de_DE ISO-8859-1 +de_DE.UTF-8 UTF-8 +de_DE@euro ISO-8859-15 +de_IT ISO-8859-1 +de_IT.UTF-8 UTF-8 +de_LI.UTF-8 UTF-8 +de_LU ISO-8859-1 +de_LU.UTF-8 UTF-8 +de_LU@euro ISO-8859-15 +doi_IN UTF-8 +dv_MV UTF-8 +dz_BT UTF-8 +el_CY ISO-8859-7 +el_CY.UTF-8 UTF-8 +el_GR ISO-8859-7 +el_GR.UTF-8 UTF-8 +en_AG UTF-8 +en_AU ISO-8859-1 +en_AU.UTF-8 UTF-8 +en_BW ISO-8859-1 +en_BW.UTF-8 UTF-8 +en_CA ISO-8859-1 +en_CA.UTF-8 UTF-8 +en_DK ISO-8859-1 +en_DK.ISO-8859-15 ISO-8859-15 +en_DK.UTF-8 UTF-8 +en_GB ISO-8859-1 +en_GB.ISO-8859-15 ISO-8859-15 +en_GB.UTF-8 UTF-8 +en_HK ISO-8859-1 +en_HK.UTF-8 UTF-8 +en_IE ISO-8859-1 +en_IE.UTF-8 UTF-8 +en_IE@euro ISO-8859-15 +en_IL UTF-8 +en_IN UTF-8 +en_NG UTF-8 +en_NZ ISO-8859-1 +en_NZ.UTF-8 UTF-8 +en_PH ISO-8859-1 +en_PH.UTF-8 UTF-8 +en_SG ISO-8859-1 +en_SG.UTF-8 UTF-8 +en_US ISO-8859-1 +en_US.ISO-8859-15 ISO-8859-15 +en_US.UTF-8 UTF-8 +en_ZA ISO-8859-1 +en_ZA.UTF-8 UTF-8 +en_ZM UTF-8 +en_ZW ISO-8859-1 +en_ZW.UTF-8 UTF-8 +eo UTF-8 +es_AR ISO-8859-1 +es_AR.UTF-8 UTF-8 +es_BO ISO-8859-1 +es_BO.UTF-8 UTF-8 +es_CL ISO-8859-1 +es_CL.UTF-8 UTF-8 +es_CO ISO-8859-1 +es_CO.UTF-8 UTF-8 +es_CR ISO-8859-1 +es_CR.UTF-8 UTF-8 +es_CU UTF-8 +es_DO ISO-8859-1 +es_DO.UTF-8 UTF-8 +es_EC ISO-8859-1 +es_EC.UTF-8 UTF-8 +es_ES ISO-8859-1 +es_ES.UTF-8 UTF-8 +es_ES@euro ISO-8859-15 +es_GT ISO-8859-1 +es_GT.UTF-8 UTF-8 +es_HN ISO-8859-1 +es_HN.UTF-8 UTF-8 +es_MX ISO-8859-1 +es_MX.UTF-8 UTF-8 +es_NI ISO-8859-1 +es_NI.UTF-8 UTF-8 +es_PA ISO-8859-1 +es_PA.UTF-8 UTF-8 +es_PE ISO-8859-1 +es_PE.UTF-8 UTF-8 +es_PR ISO-8859-1 +es_PR.UTF-8 UTF-8 +es_PY ISO-8859-1 +es_PY.UTF-8 UTF-8 +es_SV ISO-8859-1 +es_SV.UTF-8 UTF-8 +es_US ISO-8859-1 +es_US.UTF-8 UTF-8 +es_UY ISO-8859-1 +es_UY.UTF-8 UTF-8 +es_VE ISO-8859-1 +es_VE.UTF-8 UTF-8 +et_EE ISO-8859-1 +et_EE.ISO-8859-15 ISO-8859-15 +et_EE.UTF-8 UTF-8 +eu_ES ISO-8859-1 +eu_ES.UTF-8 UTF-8 +eu_ES@euro ISO-8859-15 +eu_FR ISO-8859-1 +eu_FR.UTF-8 UTF-8 +eu_FR@euro ISO-8859-15 +fa_IR UTF-8 +ff_SN UTF-8 +fi_FI ISO-8859-1 +fi_FI.UTF-8 UTF-8 +fi_FI@euro ISO-8859-15 +fil_PH UTF-8 +fo_FO ISO-8859-1 +fo_FO.UTF-8 UTF-8 +fr_BE ISO-8859-1 +fr_BE.UTF-8 UTF-8 +fr_BE@euro ISO-8859-15 +fr_CA ISO-8859-1 +fr_CA.UTF-8 UTF-8 +fr_CH ISO-8859-1 +fr_CH.UTF-8 UTF-8 +fr_FR ISO-8859-1 +fr_FR.UTF-8 UTF-8 +fr_FR@euro ISO-8859-15 +fr_LU ISO-8859-1 +fr_LU.UTF-8 UTF-8 +fr_LU@euro ISO-8859-15 +fur_IT UTF-8 +fy_DE UTF-8 +fy_NL UTF-8 +ga_IE ISO-8859-1 +ga_IE.UTF-8 UTF-8 +ga_IE@euro ISO-8859-15 +gd_GB ISO-8859-15 +gd_GB.UTF-8 UTF-8 +gez_ER UTF-8 +gez_ER@abegede UTF-8 +gez_ET UTF-8 +gez_ET@abegede UTF-8 +gl_ES ISO-8859-1 +gl_ES.UTF-8 UTF-8 +gl_ES@euro ISO-8859-15 +gu_IN UTF-8 +gv_GB ISO-8859-1 +gv_GB.UTF-8 UTF-8 +ha_NG UTF-8 +hak_TW UTF-8 +he_IL ISO-8859-8 +he_IL.UTF-8 UTF-8 +hi_IN UTF-8 +hne_IN UTF-8 +hr_HR ISO-8859-2 +hr_HR.UTF-8 UTF-8 +hsb_DE ISO-8859-2 +hsb_DE.UTF-8 UTF-8 +ht_HT UTF-8 +hu_HU ISO-8859-2 +hu_HU.UTF-8 UTF-8 +hy_AM UTF-8 +hy_AM.ARMSCII-8 ARMSCII-8 +ia_FR UTF-8 +id_ID ISO-8859-1 +id_ID.UTF-8 UTF-8 +ig_NG UTF-8 +ik_CA UTF-8 +is_IS ISO-8859-1 +is_IS.UTF-8 UTF-8 +it_CH ISO-8859-1 +it_CH.UTF-8 UTF-8 +it_IT ISO-8859-1 +it_IT.UTF-8 UTF-8 +it_IT@euro ISO-8859-15 +iu_CA UTF-8 +ja_JP.EUC-JP EUC-JP +ja_JP.UTF-8 UTF-8 +ka_GE GEORGIAN-PS +ka_GE.UTF-8 UTF-8 +kk_KZ PT154 +kk_KZ.RK1048 RK1048 +kk_KZ.UTF-8 UTF-8 +kl_GL ISO-8859-1 +kl_GL.UTF-8 UTF-8 +km_KH UTF-8 +kn_IN UTF-8 +ko_KR.EUC-KR EUC-KR +ko_KR.UTF-8 UTF-8 +kok_IN UTF-8 +ks_IN UTF-8 +ks_IN@devanagari UTF-8 +ku_TR ISO-8859-9 +ku_TR.UTF-8 UTF-8 +kw_GB ISO-8859-1 +kw_GB.UTF-8 UTF-8 +ky_KG UTF-8 +lb_LU UTF-8 +lg_UG ISO-8859-10 +lg_UG.UTF-8 UTF-8 +li_BE UTF-8 +li_NL UTF-8 +lij_IT UTF-8 +ln_CD UTF-8 +lo_LA UTF-8 +lt_LT ISO-8859-13 +lt_LT.UTF-8 UTF-8 +lv_LV ISO-8859-13 +lv_LV.UTF-8 UTF-8 +lzh_TW UTF-8 +mag_IN UTF-8 +mai_IN UTF-8 +mg_MG ISO-8859-15 +mg_MG.UTF-8 UTF-8 +mhr_RU UTF-8 +mi_NZ ISO-8859-13 +mi_NZ.UTF-8 UTF-8 +mk_MK ISO-8859-5 +mk_MK.UTF-8 UTF-8 +ml_IN UTF-8 +mn_MN UTF-8 +mni_IN UTF-8 +mr_IN UTF-8 +ms_MY ISO-8859-1 +ms_MY.UTF-8 UTF-8 +mt_MT ISO-8859-3 +mt_MT.UTF-8 UTF-8 +my_MM UTF-8 +nan_TW UTF-8 +nan_TW@latin UTF-8 +nb_NO ISO-8859-1 +nb_NO.UTF-8 UTF-8 +nds_DE UTF-8 +nds_NL UTF-8 +ne_NP UTF-8 +nhn_MX UTF-8 +niu_NU UTF-8 +niu_NZ UTF-8 +nl_AW UTF-8 +nl_BE ISO-8859-1 +nl_BE.UTF-8 UTF-8 +nl_BE@euro ISO-8859-15 +nl_NL ISO-8859-1 +nl_NL.UTF-8 UTF-8 +nl_NL@euro ISO-8859-15 +nn_NO ISO-8859-1 +nn_NO.UTF-8 UTF-8 +nr_ZA UTF-8 +nso_ZA UTF-8 +oc_FR ISO-8859-1 +oc_FR.UTF-8 UTF-8 +om_ET UTF-8 +om_KE ISO-8859-1 +om_KE.UTF-8 UTF-8 +or_IN UTF-8 +os_RU UTF-8 +pa_IN UTF-8 +pa_PK UTF-8 +pap_AW UTF-8 +pap_CW UTF-8 +pl_PL ISO-8859-2 +pl_PL.UTF-8 UTF-8 +ps_AF UTF-8 +pt_BR ISO-8859-1 +pt_BR.UTF-8 UTF-8 +pt_PT ISO-8859-1 +pt_PT.UTF-8 UTF-8 +pt_PT@euro ISO-8859-15 +quz_PE UTF-8 +raj_IN UTF-8 +ro_RO ISO-8859-2 +ro_RO.UTF-8 UTF-8 +ru_RU ISO-8859-5 +ru_RU.CP1251 CP1251 +ru_RU.KOI8-R KOI8-R +ru_RU.UTF-8 UTF-8 +ru_UA KOI8-U +ru_UA.UTF-8 UTF-8 +rw_RW UTF-8 +sa_IN UTF-8 +sat_IN UTF-8 +sc_IT UTF-8 +sd_IN UTF-8 +sd_IN@devanagari UTF-8 +se_NO UTF-8 +sgs_LT UTF-8 +shs_CA UTF-8 +si_LK UTF-8 +sid_ET UTF-8 +sk_SK ISO-8859-2 +sk_SK.UTF-8 UTF-8 +sl_SI ISO-8859-2 +sl_SI.UTF-8 UTF-8 +so_DJ ISO-8859-1 +so_DJ.UTF-8 UTF-8 +so_ET UTF-8 +so_KE ISO-8859-1 +so_KE.UTF-8 UTF-8 +so_SO ISO-8859-1 +so_SO.UTF-8 UTF-8 +sq_AL ISO-8859-1 +sq_AL.UTF-8 UTF-8 +sq_MK UTF-8 +sr_ME UTF-8 +sr_RS UTF-8 +sr_RS@latin UTF-8 +ss_ZA UTF-8 +st_ZA ISO-8859-1 +st_ZA.UTF-8 UTF-8 +sv_FI ISO-8859-1 +sv_FI.UTF-8 UTF-8 +sv_FI@euro ISO-8859-15 +sv_SE ISO-8859-1 +sv_SE.ISO-8859-15 ISO-8859-15 +sv_SE.UTF-8 UTF-8 +sw_KE UTF-8 +sw_TZ UTF-8 +szl_PL UTF-8 +ta_IN UTF-8 +ta_LK UTF-8 +tcy_IN.UTF-8 UTF-8 +te_IN UTF-8 +tg_TJ KOI8-T +tg_TJ.UTF-8 UTF-8 +th_TH TIS-620 +th_TH.UTF-8 UTF-8 +the_NP UTF-8 +ti_ER UTF-8 +ti_ET UTF-8 +tig_ER UTF-8 +tk_TM UTF-8 +tl_PH ISO-8859-1 +tl_PH.UTF-8 UTF-8 +tn_ZA UTF-8 +tr_CY ISO-8859-9 +tr_CY.UTF-8 UTF-8 +tr_TR ISO-8859-9 +tr_TR.UTF-8 UTF-8 +ts_ZA UTF-8 +tt_RU UTF-8 +tt_RU@iqtelif UTF-8 +ug_CN UTF-8 +uk_UA KOI8-U +uk_UA.UTF-8 UTF-8 +unm_US UTF-8 +ur_IN UTF-8 +ur_PK UTF-8 +uz_UZ ISO-8859-1 +uz_UZ.UTF-8 UTF-8 +uz_UZ@cyrillic UTF-8 +ve_ZA UTF-8 +vi_VN UTF-8 +wa_BE ISO-8859-1 +wa_BE.UTF-8 UTF-8 +wa_BE@euro ISO-8859-15 +wae_CH UTF-8 +wal_ET UTF-8 +wo_SN UTF-8 +xh_ZA ISO-8859-1 +xh_ZA.UTF-8 UTF-8 +yi_US CP1255 +yi_US.UTF-8 UTF-8 +yo_NG UTF-8 +yue_HK UTF-8 +zh_CN GB2312 +zh_CN.GB18030 GB18030 +zh_CN.GBK GBK +zh_CN.UTF-8 UTF-8 +zh_HK BIG5-HKSCS +zh_HK.UTF-8 UTF-8 +zh_SG GB2312 +zh_SG.GBK GBK +zh_SG.UTF-8 UTF-8 +zh_TW BIG5 +zh_TW.EUC-TW EUC-TW +zh_TW.UTF-8 UTF-8 +zu_ZA ISO-8859-1 +zu_ZA.UTF-8 UTF-8 +zu_ZA.UTF-8 UTF-8 diff --git a/build-base.sh b/build-base.sh new file mode 100755 index 00000000..ab8be6dc --- /dev/null +++ b/build-base.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Building an debian base image + +if [[ ! -f .env ]]; then + echo "Default build arguments don't exists. Creating one from default value." + cp .example.env .env +fi + +docker-compose -f docker-compose.build.yml build postgis-base + diff --git a/build-test.sh b/build-test.sh index f01d44c0..08aff95e 100755 --- a/build-test.sh +++ b/build-test.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +# For scenario testing purposes -./build.sh +if [[ ! -f .env ]]; then + echo "Default build arguments don't exists. Creating one from default value." + cp .example.env .env +fi -docker build -t kartoza/postgis:manual-build -f Dockerfile.test . +docker-compose -f docker-compose.build.yml build postgis-test diff --git a/build.sh b/build.sh index 2d0215ee..3d5f0584 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,8 @@ #!/usr/bin/env bash -docker build -t kartoza/postgis:manual-build . -docker build -t kartoza/postgis:13.0 . + +if [[ ! -f .env ]]; then + echo "Default build arguments don't exists. Creating one from default value." + cp .example.env .env +fi + +docker-compose -f docker-compose.build.yml build postgis-prod diff --git a/docker-compose.build.yml b/docker-compose.build.yml new file mode 100644 index 00000000..26d3ea95 --- /dev/null +++ b/docker-compose.build.yml @@ -0,0 +1,33 @@ +# Used solely for docker-compose build +version: '3.9' +services: + postgis-base: + image: kartoza/postgis:base-${DISTRO}-${IMAGE_VERSION}-${IMAGE_VARIANT} + build: + context: . + # Use yaml anchor for reusability + args: &build-args-anchor + DISTRO: ${DISTRO} + IMAGE_VERSION: ${IMAGE_VERSION} + IMAGE_VARIANT: ${IMAGE_VARIANT} + GENERATE_ALL_LOCALE: ${GENERATE_ALL_LOCALE} + POSTGRES_MAJOR_VERSION: ${POSTGRES_MAJOR_VERSION} + POSTGIS_MAJOR_VERSION: ${POSTGIS_MAJOR_VERSION} + POSTGIS_MINOR_RELEASE: ${POSTGIS_MINOR_RELEASE} + target: postgis-base + + postgis-prod: + image: kartoza/postgis:${POSTGRES_MAJOR_VERSION}-${POSTGIS_MAJOR_VERSION}.${POSTGIS_MINOR_RELEASE} + build: + context: . + args: + <<: *build-args-anchor + target: postgis-prod + + postgis-test: + image: kartoza/postgis:manual-build + build: + context: . + args: + <<: *build-args-anchor + target: postgis-test diff --git a/docker-compose.yml b/docker-compose.yml index 481a9f74..5f2a0a16 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,9 @@ volumes: services: db: - image: kartoza/postgis:12.0 + image: kartoza/postgis:13-3.1 volumes: - - postgis-data:/var/lib/postgresql + - postgis-data:/var/lib/postgresql/data - dbbackups:/backups environment: # If you need to create multiple database you can add coma separated databases eg gis,data @@ -26,7 +26,7 @@ services: test: "exit 0" dbbackups: - image: kartoza/pg-backup:12.0 + image: kartoza/pg-backup:13.0 hostname: pg-backups volumes: - dbbackups:/backups diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..d765ccc2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +docker-compose==1.28 \ No newline at end of file diff --git a/sample/logical_replication/docker-compose.yml b/sample/logical_replication/docker-compose.yml index bdc44606..95b9bc7e 100644 --- a/sample/logical_replication/docker-compose.yml +++ b/sample/logical_replication/docker-compose.yml @@ -8,7 +8,7 @@ volumes: services: pg-publisher: - image: kartoza/postgis:13.0 + image: kartoza/postgis:13-3.1 restart: 'always' volumes: - pg-publisher-data-dir:/var/lib/postgresql @@ -25,7 +25,7 @@ services: test: "exit 0" pg-subscriber: - image: kartoza/postgis:13.0 + image: kartoza/postgis:13-3.1 restart: 'always' volumes: - pg-subscriber-data-dir:/var/lib/postgresql diff --git a/sample/replication/docker-compose.yml b/sample/replication/docker-compose.yml index 516076c5..57a6e1bc 100644 --- a/sample/replication/docker-compose.yml +++ b/sample/replication/docker-compose.yml @@ -8,7 +8,7 @@ volumes: services: pg-master: - image: 'kartoza/postgis:13.0' + image: kartoza/postgis:13-3.1 restart: 'always' # You can optionally mount to volume, to play with the persistence and # observe how the slave will behave after restarts. @@ -35,7 +35,7 @@ services: test: "exit 0" pg-slave: - image: 'kartoza/postgis:13.0' + image: kartoza/postgis:13-3.1 restart: 'always' # You can optionally mount to volume, but we're not able to scale it # in that case. diff --git a/scenario_tests/collations/docker-compose.yml b/scenario_tests/collations/docker-compose.yml index f3239edf..577fd8ad 100644 --- a/scenario_tests/collations/docker-compose.yml +++ b/scenario_tests/collations/docker-compose.yml @@ -20,6 +20,7 @@ services: DEFAULT_CTYPE: ${DEFAULT_COLLATION:-id_ID.utf8} ALLOW_IP_RANGE: '0.0.0.0/0' TEST_CLASS: test_collation.TestCollationDefault + POSTGRES_PASS: 'docker' ports: - "7777:5432" healthcheck: @@ -45,6 +46,7 @@ services: DEFAULT_CTYPE: ${DEFAULT_COLLATION:-id_ID.utf8} ALLOW_IP_RANGE: '0.0.0.0/0' TEST_CLASS: test_collation.TestCollationInitialization + POSTGRES_PASS: 'docker' ports: - "7776:5432" healthcheck: diff --git a/scenario_tests/collations/test.sh b/scenario_tests/collations/test.sh index 28a39532..703fb2ef 100755 --- a/scenario_tests/collations/test.sh +++ b/scenario_tests/collations/test.sh @@ -8,6 +8,10 @@ source ../test-env.sh # Run service docker-compose up -d +if [[ -n "${PRINT_TEST_LOGS}" ]]; then + docker-compose logs -f & +fi + sleep 30 services=("pg" "pg-new") @@ -15,10 +19,12 @@ services=("pg" "pg-new") for service in "${services[@]}"; do # Execute tests - until docker-compose exec $service pg_isready; do + until docker-compose exec -T $service pg_isready; do sleep 30 + echo "Wait service to be ready" done; - docker-compose exec $service /bin/bash /tests/test.sh + echo "Execute test for $service" + docker-compose exec -T $service /bin/bash /tests/test.sh done diff --git a/scenario_tests/datadir_init/docker-compose.yml b/scenario_tests/datadir_init/docker-compose.yml index 6755a3d2..9a1c4f07 100644 --- a/scenario_tests/datadir_init/docker-compose.yml +++ b/scenario_tests/datadir_init/docker-compose.yml @@ -2,7 +2,10 @@ version: '2.1' volumes: default-pg-data-dir: new-pg-data-dir: + new-pg-data-dir-2: + new-pg-data-dir-3: recreate-pg-data-dir: + init-waldir: services: pg-default: image: 'kartoza/postgis:${TAG:-manual-build}' @@ -14,6 +17,7 @@ services: environment: # Default usage, no datadir location defined TEST_CLASS: TestDefault + POSTGRES_PASS: 'docker' healthcheck: interval: 60s timeout: 30s @@ -31,6 +35,7 @@ services: # Tell the new location TEST_CLASS: TestNew DATADIR: /opt/mypostgis/data + POSTGRES_PASS: 'docker' healthcheck: interval: 60s timeout: 30s @@ -50,8 +55,89 @@ services: DEFAULT_ENCODING: ${DEFAULT_ENCODING:-UTF-8} DEFAULT_COLLATION: ${DEFAULT_COLLATION:-id_ID.utf8} DEFAULT_CTYPE: ${DEFAULT_COLLATION:-id_ID.utf8} + POSTGRES_PASS: 'docker' healthcheck: interval: 60s timeout: 30s retries: 3 test: "pg_isready" + + pg-custom-waldir-wrong: + image: 'kartoza/postgis:${TAG:-manual-build}' + volumes: + # Mount to a locations where there are initial data + - new-pg-data-dir-2:/opt/mypostgis/data + # Specify different waldir location + - init-waldir:/opt/mypostgis/data/waldir + - ./tests:/tests + - ../utils:/lib/utils + environment: + TEST_CLASS: TestCustomWALdir + DATADIR: /opt/mypostgis/data + POSTGRES_INITDB_WALDIR: /opt/mypostgis/data/waldir + POSTGRES_PASS: 'docker' + healthcheck: + interval: 60s + timeout: 30s + retries: 3 + test: "pg_isready" + + pg-custom-waldir-correct: + image: 'kartoza/postgis:${TAG:-manual-build}' + volumes: + # Mount to new locations where there are no initial data + - new-pg-data-dir-3:/opt/mypostgis/data + # Specify different waldir location + - init-waldir:/opt/mypostgis/waldir + - ./tests:/tests + - ../utils:/lib/utils + environment: + TEST_CLASS: TestCustomWALdir + DATADIR: /opt/mypostgis/data + POSTGRES_INITDB_WALDIR: /opt/mypostgis/waldir + POSTGRES_PASS: 'docker' + healthcheck: + interval: 60s + timeout: 30s + retries: 3 + test: "pg_isready" + + pg-custom-waldir-not-match-1: + image: 'kartoza/postgis:${TAG:-manual-build}' + volumes: + # Mount to a locations where there are initial data + - new-pg-data-dir-3:/opt/mypostgis/data + # Specify different waldir location + - init-waldir:/opt/mypostgis/waldir + - ./tests:/tests + - ../utils:/lib/utils + environment: + TEST_CLASS: TestCustomWALdirNotMatch + DATADIR: /opt/mypostgis/data + POSTGRES_INITDB_WALDIR: /opt/waldir + POSTGRES_PASS: 'docker' + healthcheck: + interval: 60s + timeout: 30s + retries: 3 + test: "pg_isready" + + pg-custom-waldir-not-match-2: + image: 'kartoza/postgis:${TAG:-manual-build}' + volumes: + # Mount to a locations where there are initial data + - new-pg-data-dir-2:/opt/mypostgis/data + # Specify different waldir location + - init-waldir:/opt/waldir + - ./tests:/tests + - ../utils:/lib/utils + environment: + TEST_CLASS: TestCustomWALdirNotMatch + DATADIR: /opt/mypostgis/data + POSTGRES_INITDB_WALDIR: /opt/waldir + POSTGRES_PASS: 'docker' + healthcheck: + interval: 60s + timeout: 30s + retries: 3 + test: "pg_isready" \ No newline at end of file diff --git a/scenario_tests/datadir_init/test.sh b/scenario_tests/datadir_init/test.sh index 4c041c50..d008ef79 100755 --- a/scenario_tests/datadir_init/test.sh +++ b/scenario_tests/datadir_init/test.sh @@ -6,7 +6,11 @@ set -e source ../test-env.sh # Run service -docker-compose up -d +docker-compose up -d pg-default pg-new pg-recreate + +if [[ -n "${PRINT_TEST_LOGS}" ]]; then + docker-compose logs -f & +fi sleep 60 @@ -15,11 +19,16 @@ services=("pg-default" "pg-new" "pg-recreate") for service in "${services[@]}"; do # Execute tests - until docker-compose exec $service pg_isready; do - sleep 1 + until docker-compose exec -T $service pg_isready; do + sleep 5 + echo "Wait service to be ready" done; - docker-compose exec $service /bin/bash /tests/test.sh + echo "Execute test for $service" + docker-compose exec -T $service /bin/bash /tests/test.sh done +# special meta test to check the setup +bash ./test_custom_waldir.sh + docker-compose down -v diff --git a/scenario_tests/datadir_init/test_custom_waldir.sh b/scenario_tests/datadir_init/test_custom_waldir.sh new file mode 100644 index 00000000..63e48ff9 --- /dev/null +++ b/scenario_tests/datadir_init/test_custom_waldir.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash + +# exit immediately if test fails +set -e + +source ../test-env.sh + +# This test is special +# It is used to check the meta level of the setup. + +# Print logs +if [[ -n "${PRINT_TEST_LOGS}" ]]; then + docker-compose logs -f & +fi + +# Recreate containers with the same setup as pg-new and pg-default +# Try to make sure that container recreation is successful +echo "### Checking Container Recreation" +docker-compose down +docker-compose up -d pg-default pg-new pg-recreate + +sleep 60 + +services=("pg-default" "pg-new" "pg-recreate") + +for service in "${services[@]}"; do + + # Execute tests + until docker-compose exec -T $service pg_isready; do + sleep 5 + echo "Wait service to be ready" + done; + echo "Execute test for $service" + docker-compose exec -T $service /bin/bash /tests/test.sh + +done + +# Check the wrong setup must have warned that nested custom pg_wal location +# is prevented +echo "### Checking Error Message on nested pg_wal location" +service="pg-custom-waldir-wrong" +docker-compose up -d pg-custom-waldir-wrong + +sleep 60 + +# Loop until we found error message +while true; do + if [[ -n "$(docker-compose logs $service | grep 'Error')" && \ + -n "$(docker-compose logs $service | grep 'POSTGRES_INITDB_WALDIR should not be set to be inside DATADIR or PGDATA.')" ]]; then + break + fi + sleep 5 +done; + +docker-compose down + +# Check that the correct custom initdb waldir works, twice after container restart. +echo "### Checking custom POSTGRES_INITDB_WALDIR should work" +service="pg-custom-waldir-correct" +for ((i=1;i<=2;i++)); do + echo "attempt $i" + docker-compose up -d $service + sleep 60 + until docker-compose exec -T $service pg_isready; do + sleep 5 + echo "Wait service to be ready" + done; + echo "Execute test for $service" + docker-compose exec -T $service /bin/bash /tests/test.sh + docker-compose down +done + +# Check that if the variable POSTGRES_INITBD_WALDIR doesn't match with pg_wal symlink, +# then give warning, but proceeds if the the mount is still correct +echo "### Checking raise warning if custom POSTGRES_INITDB_WALDIR does not match" +service="pg-custom-waldir-not-match-1" +docker-compose up -d $service +sleep 60 +# Loop until we found warning message +while true; do + if [[ -n "$(docker-compose logs $service | grep 'Warning')" && \ + -n "$(docker-compose logs $service | grep 'POSTGRES_INITDB_WALDIR is not the same as what pg_wal is pointing to.')" ]]; then + break + fi + sleep 5 +done; +until docker-compose exec -T $service pg_isready; do + sleep 5 + echo "Wait service to be ready" +done; +echo "Execute test for $service" +docker-compose exec -T $service /bin/bash /tests/test.sh +docker-compose down + +# Check that if the pg_wal is empty, then something is wrong and we should exit +echo "### Checking Error and Exit if pg_wal is empty" +service="pg-custom-waldir-not-match-2" +docker-compose up -d $service +sleep 60 +# Loop until we found warning message +warning_text="Can't proceed because \"/opt/mypostgis/data/pg_wal\" directory is empty." +while true; do + if [[ -n "$(docker-compose logs $service | grep 'Error')" && \ + -n "$(docker-compose logs $service | grep "$warning_text")" ]]; then + break + fi + sleep 5 +done; + +docker-compose down -v diff --git a/scenario_tests/datadir_init/tests/test_datadir.py b/scenario_tests/datadir_init/tests/test_datadir.py index 99897b00..1bef318c 100644 --- a/scenario_tests/datadir_init/tests/test_datadir.py +++ b/scenario_tests/datadir_init/tests/test_datadir.py @@ -1,6 +1,7 @@ import unittest import os from utils.utils import DBConnection +from pathlib import Path class TestCollationBase(unittest.TestCase): @@ -78,3 +79,35 @@ def test_check_collation_in_new_datadir(self): self.assertEqual(dbcollate, os.environ.get('DEFAULT_COLLATION')) self.assertEqual(dbctype, os.environ.get('DEFAULT_CTYPE')) + +class TestCustomWALdir(TestCollationBase): + + def test_check_pg_wal_symlink(self): + self.db.conn.autocommit = True + postgres_initdb_waldir = os.environ.get('POSTGRES_INITDB_WALDIR') + with self.db.cursor() as c: + datadir_location = self.fetch_datadir_location(c) + pg_wal_symlink = os.path.join(datadir_location, 'pg_wal') + # In this correct setup, pg_wal symlink must resolve to the + # correct POSTGRES_INITDB_WALDIR location + self.assertTrue( + Path(pg_wal_symlink).resolve().match(postgres_initdb_waldir)) + + +class TestCustomWALdirNotMatch(TestCollationBase): + + def test_check_pg_wal_symlink(self): + self.db.conn.autocommit = True + postgres_initdb_waldir = os.environ.get('POSTGRES_INITDB_WALDIR') + with self.db.cursor() as c: + datadir_location = self.fetch_datadir_location(c) + pg_wal_symlink = os.path.join(datadir_location, 'pg_wal') + # In this wrong setup, pg_wal symlink and POSTGRES_INITDB_WALDIR + # must resolve to a different path to raise the warning + self.assertFalse( + Path(pg_wal_symlink).resolve().match(postgres_initdb_waldir)) + + # It has different path, but if this unittests runs, that means + # postgres was able to start and the pg_wal symlink contains correct + # data + self.assertTrue(os.listdir(pg_wal_symlink)) diff --git a/scenario_tests/extensions/docker-compose.yml b/scenario_tests/extensions/docker-compose.yml index ec054ad8..00eb3e32 100644 --- a/scenario_tests/extensions/docker-compose.yml +++ b/scenario_tests/extensions/docker-compose.yml @@ -13,6 +13,7 @@ services: environment: ALLOW_IP_RANGE: '0.0.0.0/0' TEST_CLASS: test_extensions.TestExtensions + POSTGRES_PASS: 'docker' ports: - "7777:5432" healthcheck: @@ -33,6 +34,7 @@ services: ALLOW_IP_RANGE: '0.0.0.0/0' TEST_CLASS: test_extensions.TestExtensions POSTGRES_MULTIPLE_EXTENSIONS: postgis,pgrouting + POSTGRES_PASS: 'docker' ports: - "7776:5432" healthcheck: diff --git a/scenario_tests/extensions/test.sh b/scenario_tests/extensions/test.sh index d1e4dd73..06131dfe 100755 --- a/scenario_tests/extensions/test.sh +++ b/scenario_tests/extensions/test.sh @@ -8,6 +8,10 @@ source ../test-env.sh # Run service docker-compose up -d +if [[ -n "${PRINT_TEST_LOGS}" ]]; then + docker-compose logs -f & +fi + sleep 30 services=("pg" "pg-two-extensions") @@ -15,10 +19,12 @@ services=("pg" "pg-two-extensions") for service in "${services[@]}"; do # Execute tests - until docker-compose exec $service pg_isready; do + until docker-compose exec -T $service pg_isready; do sleep 30 + echo "Wait service to be ready" done; - docker-compose exec $service /bin/bash /tests/test.sh + echo "Execute test for $service" + docker-compose exec -T $service /bin/bash /tests/test.sh done diff --git a/scenario_tests/logical_replication/docker-compose.yml b/scenario_tests/logical_replication/docker-compose.yml index b5f27df8..a6b1242c 100644 --- a/scenario_tests/logical_replication/docker-compose.yml +++ b/scenario_tests/logical_replication/docker-compose.yml @@ -17,6 +17,7 @@ services: - ../utils:/lib/utils environment: ALLOW_IP_RANGE: '0.0.0.0/0' + POSTGRES_PASS: 'docker' REPLICATION_USER: 'replicator' REPLICATION_PASS: 'replicator' REPLICATION: 'true' @@ -43,12 +44,12 @@ services: environment: ALLOW_IP_RANGE: '0.0.0.0/0' WAL_LEVEL: 'logical' + POSTGRES_PASS: 'docker' REPLICATION_USER: 'replicator' REPLICATION_PASS: 'replicator' REPLICATION: 'true' depends_on: - pg-publisher: - condition: service_healthy + - pg-publisher # You can expose the port to observe it in your local machine # For this sample, it was disabled by default to allow scaling test ports: diff --git a/scenario_tests/logical_replication/test.sh b/scenario_tests/logical_replication/test.sh index b0945c8a..36eaf4e1 100755 --- a/scenario_tests/logical_replication/test.sh +++ b/scenario_tests/logical_replication/test.sh @@ -8,22 +8,26 @@ source ../test-env.sh # Run service docker-compose up -d -sleep 5 +if [[ -n "${PRINT_TEST_LOGS}" ]]; then + docker-compose logs -f & +fi + +sleep 60 # Preparing publisher cluster -until docker-compose exec pg-publisher pg_isready; do +until docker-compose exec -T pg-publisher pg_isready; do sleep 1 done; # Execute tests -docker-compose exec pg-publisher /bin/bash /tests/test_publisher.sh +docker-compose exec -T pg-publisher /bin/bash /tests/test_publisher.sh # Preparing node cluster -until docker-compose exec pg-subscriber pg_isready; do +until docker-compose exec -T pg-subscriber pg_isready; do sleep 1 done; # Execute tests -docker-compose exec pg-subscriber /bin/bash /tests/test_subscriber.sh +docker-compose exec -T pg-subscriber /bin/bash /tests/test_subscriber.sh docker-compose down -v diff --git a/scenario_tests/logical_replication/tests/test_logical_replication.py b/scenario_tests/logical_replication/tests/test_logical_replication.py index 7286752b..49638c47 100644 --- a/scenario_tests/logical_replication/tests/test_logical_replication.py +++ b/scenario_tests/logical_replication/tests/test_logical_replication.py @@ -72,7 +72,7 @@ def assert_in_loop( try: output = func_action() func_assert(output) - print('Assertion succes') + print('Assertion success') return except Exception as e: last_error = e diff --git a/scenario_tests/replications/test.sh b/scenario_tests/replications/test.sh deleted file mode 100755 index cd7b07c9..00000000 --- a/scenario_tests/replications/test.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# exit immediately if test fails -set -e - -source ../test-env.sh - -# Run service -docker-compose up -d - -sleep 5 - -# Preparing master cluster -until docker-compose exec pg-master pg_isready; do - sleep 1 -done; - -# Execute tests -docker-compose exec pg-master /bin/bash /tests/test_master.sh - -# Preparing node cluster -until docker-compose exec pg-node pg_isready; do - sleep 1 -done; - -# Execute tests -docker-compose exec pg-node /bin/bash /tests/test_node.sh - -docker-compose down -v diff --git a/scenario_tests/replications/docker-compose.yml b/scenario_tests/streaming_replication/docker-compose.yml similarity index 98% rename from scenario_tests/replications/docker-compose.yml rename to scenario_tests/streaming_replication/docker-compose.yml index f3a56142..16069e33 100644 --- a/scenario_tests/replications/docker-compose.yml +++ b/scenario_tests/streaming_replication/docker-compose.yml @@ -22,6 +22,7 @@ services: ALLOW_IP_RANGE: '0.0.0.0/0' # We can specify optional credentials + POSTGRES_PASS: 'docker' REPLICATION_USER: 'replicator' REPLICATION_PASS: 'replicator' REPLICATION: 'true' @@ -61,6 +62,7 @@ services: # REPLICATE_FROM options accepts domain-name or IP address # with this in mind, you can also put docker service name, because it # will be resolved as host name. + POSTGRES_PASS: 'docker' REPLICATE_FROM: 'pg-master' REPLICATION: 'true' diff --git a/scenario_tests/streaming_replication/test.sh b/scenario_tests/streaming_replication/test.sh new file mode 100755 index 00000000..5ddb0e81 --- /dev/null +++ b/scenario_tests/streaming_replication/test.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +# exit immediately if test fails +set -e + +source ../test-env.sh + +# Run service +docker-compose up -d + +if [[ -n "${PRINT_TEST_LOGS}" ]]; then + docker-compose logs -f & +fi + +sleep 30 + +# Preparing master cluster +until docker-compose exec -T pg-master pg_isready; do + sleep 30 +done; + +# Execute tests +docker-compose exec -T pg-master /bin/bash /tests/test_master.sh + +# Preparing node cluster +until docker-compose exec -T pg-node pg_isready; do + sleep 30 +done; + +# Execute tests +docker-compose exec -T pg-node /bin/bash /tests/test_node.sh + +docker-compose down -v diff --git a/scenario_tests/replications/tests/__init__.py b/scenario_tests/streaming_replication/tests/__init__.py similarity index 100% rename from scenario_tests/replications/tests/__init__.py rename to scenario_tests/streaming_replication/tests/__init__.py diff --git a/scenario_tests/replications/tests/test_master.sh b/scenario_tests/streaming_replication/tests/test_master.sh similarity index 100% rename from scenario_tests/replications/tests/test_master.sh rename to scenario_tests/streaming_replication/tests/test_master.sh diff --git a/scenario_tests/replications/tests/test_node.sh b/scenario_tests/streaming_replication/tests/test_node.sh similarity index 100% rename from scenario_tests/replications/tests/test_node.sh rename to scenario_tests/streaming_replication/tests/test_node.sh diff --git a/scenario_tests/replications/tests/test_replication.py b/scenario_tests/streaming_replication/tests/test_replication.py similarity index 100% rename from scenario_tests/replications/tests/test_replication.py rename to scenario_tests/streaming_replication/tests/test_replication.py diff --git a/scripts/docker-entrypoint.sh b/scripts/docker-entrypoint.sh index 6a61470e..3cdb7beb 100755 --- a/scripts/docker-entrypoint.sh +++ b/scripts/docker-entrypoint.sh @@ -2,6 +2,18 @@ set -e +#Setup VPN +if [ -f "/scripts/setup-vpn.sh" ]; then + # Lancer le script s'il existe + echo "Lancement du script openvpn." + source /scripts/setup-vpn.sh +else + # Afficher un message d'erreur si le script n'existe pas + echo "Le script setup-vpn existe pas." +fi + +#Variables environnement + source /scripts/env-data.sh # Setup postgres CONF file @@ -15,6 +27,15 @@ source /scripts/setup-ssl.sh source /scripts/setup-pg_hba.sh + + +# Function to add figlet +figlet -t "Kartoza Docker PostGIS" + +POSTGRES_PASS=$(cat /tmp/PGPASSWORD.txt) +echo -e "[Entrypoint] GENERATED Postgres PASSWORD: \e[1;31m $POSTGRES_PASS" +echo -e "\033[0m PGPASSWORD Generated above: " + if [[ -z "$REPLICATE_FROM" ]]; then # This means this is a master instance. We check that database exists echo "Setup master database" @@ -43,4 +64,5 @@ if [[ "${1:0:1}" = '-' ]]; then set -- postgres "$@" fi + exec su - "$@" diff --git a/scripts/env-data.sh b/scripts/env-data.sh index f288f83e..07ae92a4 100644 --- a/scripts/env-data.sh +++ b/scripts/env-data.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash POSTGRES_MAJOR_VERSION=$(cat /tmp/pg_version.txt) +POSTGIS_MAJOR=$(cat /tmp/pg_major_version.txt) +POSTGIS_MINOR_RELEASE=$(cat /tmp/pg_minor_version.txt) DEFAULT_DATADIR="/var/lib/postgresql/${POSTGRES_MAJOR_VERSION}/main" +# Commented for documentation. You can specify the location of +# pg_wal directory/volume using the following environment variable: +# POSTGRES_INITDB_WALDIR (default value is unset) ROOT_CONF="/etc/postgresql/${POSTGRES_MAJOR_VERSION}/main" PG_ENV="$ROOT_CONF/environment" CONF="$ROOT_CONF/postgresql.conf" @@ -8,7 +13,7 @@ WAL_ARCHIVE="/opt/archivedir" RECOVERY_CONF="$ROOT_CONF/recovery.conf" POSTGRES="/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin/postgres" INITDB="/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin/initdb" -SQLDIR="/usr/share/postgresql/${POSTGRES_MAJOR_VERSION}/contrib/postgis-3.0/" +SQLDIR="/usr/share/postgresql/${POSTGRES_MAJOR_VERSION}/contrib/postgis-${POSTGIS_MAJOR}.${POSTGIS_MINOR_RELEASE}/" SETVARS="POSTGIS_ENABLE_OUTDB_RASTERS=1 POSTGIS_GDAL_ENABLED_DRIVERS=ENABLE_ALL" LOCALONLY="-c listen_addresses='127.0.0.1'" PG_BASEBACKUP="/usr/bin/pg_basebackup" @@ -17,6 +22,7 @@ PGSTAT_TMP="/var/run/postgresql/" PG_PID="/var/run/postgresql/${POSTGRES_MAJOR_VERSION}-main.pid" + # Read data from secrets into env variables. # usage: file_env VAR [DEFAULT] @@ -65,13 +71,14 @@ then mkdir -p ${DATA_PATH} fi } + + # Make sure we have a user set up if [ -z "${POSTGRES_USER}" ]; then POSTGRES_USER=docker fi -if [ -z "${POSTGRES_PASS}" ]; then - POSTGRES_PASS=docker -fi + + if [ -z "${POSTGRES_DBNAME}" ]; then POSTGRES_DBNAME=gis fi @@ -79,6 +86,7 @@ fi if [ -z "${DATADIR}" ]; then DATADIR=${DEFAULT_DATADIR} fi + # RECREATE_DATADIR flag default value # Always assume that we don't want to recreate datadir if not explicitly defined # For issue: https://github.com/kartoza/docker-postgis/issues/226 @@ -87,6 +95,10 @@ if [ -z "${RECREATE_DATADIR}" ]; then else RECREATE_DATADIR=$(boolean ${RECREATE_DATADIR}) fi +if [ -z "${SSL_DIR}" ]; then + SSL_DIR="/ssl_certificates" +fi + # SSL mode if [ -z "${PGSSLMODE}" ]; then PGSSLMODE=require @@ -239,23 +251,39 @@ if [ -z "${REPLICATION_USER}" ]; then REPLICATION_USER=replicator fi -if [ -z "${REPLICATION_PASS}" ]; then - REPLICATION_PASS=replicator -fi +if [ -z "$IGNORE_INIT_HOOK_LOCKFILE" ]; then + IGNORE_INIT_HOOK_LOCKFILE=false +fi if [ -z "$EXTRA_CONF" ]; then EXTRA_CONF="" fi if [ -z "${SHARED_PRELOAD_LIBRARIES}" ]; then - SHARED_PRELOAD_LIBRARIES='pg_cron' + SHARED_PRELOAD_LIBRARIES='pg_cron,timescaledb' fi if [ -z "$PASSWORD_AUTHENTICATION" ]; then PASSWORD_AUTHENTICATION="scram-sha-256" fi +if [ -z "${ALL_DATABASES}" ]; then + ALL_DATABASES=FALSE +fi + +if [ -z "${FORCE_SSL}" ]; then + FORCE_SSL=FALSE +fi + +if [ -z "${ACCEPT_TIMESCALE_TUNING}" ]; then + ACCEPT_TIMESCALE_TUNING=FALSE +fi + +if [ -z "${TIMESCALE_TUNING_PARAMS}" ]; then + TIMESCALE_TUNING_PARAMS= +fi + # Compatibility with official postgres variable # Official postgres variable gets priority if [ -n "${POSTGRES_PASSWORD}" ]; then @@ -318,7 +346,7 @@ function restart_postgres { function entry_point_script { SETUP_LOCKFILE="/docker-entrypoint-initdb.d/.entry_point.lock" # If lockfile doesn't exists, proceed. - if [[ ! -f "${SETUP_LOCKFILE}" ]]; then + if [[ ! -f "${SETUP_LOCKFILE}" ]] || [ "${IGNORE_INIT_HOOK_LOCKFILE}" == true ]; then if find "/docker-entrypoint-initdb.d" -mindepth 1 -print -quit 2>/dev/null | grep -q .; then for f in /docker-entrypoint-initdb.d/*; do export PGPASSWORD=${POSTGRES_PASS} @@ -337,3 +365,50 @@ function entry_point_script { return 0 } + +function configure_replication_permissions { + + echo "Setup data permissions" + echo "----------------------" + chown -R postgres:postgres $(getent passwd postgres | cut -d: -f6) + su - postgres -c "echo \"${REPLICATE_FROM}:${REPLICATE_PORT}:*:${REPLICATION_USER}:${REPLICATION_PASS}\" > ~/.pgpass" + su - postgres -c "chmod 0600 ~/.pgpass" +} + +function streaming_replication { +until su - postgres -c "${PG_BASEBACKUP} -X stream -h ${REPLICATE_FROM} -p ${REPLICATE_PORT} -D ${DATADIR} -U ${REPLICATION_USER} -R -vP -w --label=gis_pg_custer" + do + echo "Waiting for master to connect..." + sleep 1s + if [[ "$(ls -A ${DATADIR})" ]]; then + echo "Need empty folder. Cleaning directory..." + rm -rf ${DATADIR}/* + fi + done + +} + +function pg_password() { + SETUP_LOCKFILE="/settings/.pgpasspass.lock" + if [ -z "${POSTGRES_PASS}" ] && [ ! -f ${SETUP_LOCKFILE} ]; then + POSTGRES_PASS=$(openssl rand -base64 15) + touch ${SETUP_LOCKFILE} + echo "$POSTGRES_PASS" > /tmp/PGPASSWORD.txt + else + echo "$POSTGRES_PASS" > /tmp/PGPASSWORD.txt + fi + +} + +function replication_password() { + SETUP_LOCKFILE="/settings/.replicationpass.lock" + if [ -z "${REPLICATION_PASS}" ] && [ ! -f ${SETUP_LOCKFILE} ]; then + REPLICATION_PASS=$(openssl rand -base64 15) + touch ${SETUP_LOCKFILE} + echo "$REPLICATION_PASS" > /tmp/REPLPASSWORD.txt + else + echo "$REPLICATION_PASS" > /tmp/REPLPASSWORD.txt + fi + +} + diff --git a/scripts/setup-conf.sh b/scripts/setup-conf.sh index 5c214c83..484685a3 100644 --- a/scripts/setup-conf.sh +++ b/scripts/setup-conf.sh @@ -3,25 +3,22 @@ source /scripts/env-data.sh SETUP_LOCKFILE="${ROOT_CONF}/.postgresql.conf.lock" +create_dir /settings if [ -f "${SETUP_LOCKFILE}" ]; then return 0 fi -list=(`echo ${POSTGRES_DBNAME} | tr ',' ' '`) -arr=(${list}) -SINGLE_DB=${arr[0]} -# This script will setup necessary configuration to enable replications - # Refresh configuration in case environment settings changed. cat $CONF.template > $CONF -# Reflect DATADIR loaction +# Reflect DATA DIR location # Delete any data_dir declarations sed -i '/data_directory/d' $CONF -echo "data_directory = '${DATADIR}'" >> $CONF -# This script will setup necessary configuration to optimise for PostGIS and to enable replications -cat >> $CONF < ${ROOT_CONF}/postgis.conf <> $CONF +# Create a config for logical replication if [[ "${REPLICATION}" =~ [Tt][Rr][Uu][Ee] && "$WAL_LEVEL" == 'logical' ]]; then -cat >> "$CONF" < ${ROOT_CONF}/logical_replication.conf <> $CONF fi +# Create a config for streaming replication if [[ "${REPLICATION}" =~ [Tt][Rr][Uu][Ee] && "$WAL_LEVEL" == 'replica' ]]; then -cat >> "$CONF" < ${ROOT_CONF}/streaming_replication.conf <> $CONF fi -echo -e $EXTRA_CONF >> $CONF +if [[ ! -f ${ROOT_CONF}/extra.conf ]]; then + # If it doesn't exists, copy from /settings directory if exists + if [[ -f /settings/extra.conf ]]; then + cp -f /settings/extra.conf ${ROOT_CONF}/extra.conf + echo "include 'extra.conf'" >> $CONF + else + # default value + if [[ -n "$EXTRA_CONF" ]]; then + echo -e $EXTRA_CONF >> ${ROOT_CONF}/extra.conf + echo "include 'extra.conf'" >> $CONF + fi + fi + +fi + +# Timescale default tuning +# TODO If timescale DB accepts reading from include directory then refactor code to remove line 97 - 112 (https://github.com/timescale/timescaledb-tune/issues/80) +if [[ ${ACCEPT_TIMESCALE_TUNING} =~ [Tt][Rr][Uu][Ee] ]];then + if [[ -f ${ROOT_CONF}/postgis.conf ]];then + sed -i '/postgis.conf/d' "${ROOT_CONF}"/postgresql.conf + cat "${ROOT_CONF}"/postgis.conf >> "${ROOT_CONF}"/postgresql.conf + fi + if [[ -f ${ROOT_CONF}/logical_replication.conf ]];then + sed -i '/logical_replication.conf/d' "${ROOT_CONF}"/postgresql.conf + cat "${ROOT_CONF}"/logical_replication.conf >> "${ROOT_CONF}"/postgresql.conf + fi + if [[ -f ${ROOT_CONF}/streaming_replication.conf ]];then + sed -i '/streaming_replication.conf/d' "${ROOT_CONF}"/postgresql.conf + cat "${ROOT_CONF}"/streaming_replication.conf >> "${ROOT_CONF}"/postgresql.conf + fi + if [[ -f ${ROOT_CONF}/extra.conf ]];then + sed -i '/extra.conf/d' "${ROOT_CONF}"/postgresql.conf + cat "${ROOT_CONF}"/extra.conf >> "${ROOT_CONF}"/postgresql.conf + fi + echo -e "\e[1;31m Time scale config tuning values below" + # TODO Add logic to find defaults memory, CPUS as these can vary from defaults on host machine and in docker container + timescaledb-tune -yes -quiet "${TIMESCALE_TUNING_PARAMS}" --conf-path="${ROOT_CONF}"/postgresql.conf + echo -e "\033[0m Time scale config tuning values set in ${ROOT_CONF}/postgresql.conf" +fi # Optimise PostgreSQL shared memory for PostGIS # shmall units are pages and shmmax units are bytes(?) equivalent to the desired shared_buffer size set in setup_conf.sh - in this case 500MB diff --git a/scripts/setup-database.sh b/scripts/setup-database.sh index c255f6b8..00fb9bea 100644 --- a/scripts/setup-database.sh +++ b/scripts/setup-database.sh @@ -2,26 +2,77 @@ source /scripts/env-data.sh +POSTGRES_PASS=$(cat /tmp/PGPASSWORD.txt) +INITDB_WALDIR_FLAG="" + +# Check POSTGRES_INITDB_WALDIR value +if [[ -n "${POSTGRES_INITDB_WALDIR}" ]]; then + # If POSTGRES_INITDB_WALDIR is defined, make sure that it is not inside + # the ${DATADIR} directory, to avoid deletions + case "${POSTGRES_INITDB_WALDIR}" in + ${DATADIR}/*) + # In this case, we have to fail early + echo "POSTGRES_INITDB_WALDIR should not be set to be inside DATADIR or PGDATA" +cat << EOF 1>&2 +Error! +POSTGRES_INITDB_WALDIR should not be set to be inside DATADIR or PGDATA. +POSTGRES_INITDB_WALDIR: ${POSTGRES_INITDB_WALDIR} +DATADIR or PGDATA: ${DATADIR} +EOF + exit 1 + ;; + *) + # For other case, make sure the directory is created with proper permissions + create_dir "${POSTGRES_INITDB_WALDIR}" + chown -R postgres:postgres ${POSTGRES_INITDB_WALDIR} + ;; + esac + # Set the --waldir flag for postgres initialization + INITDB_WALDIR_FLAG="--waldir ${POSTGRES_INITDB_WALDIR}" +fi + # test if DATADIR has content -# Do initialization if DATADIR is empty, or RECREATE_DATADIR is true -if [[ -z "$(ls -A ${DATADIR} 2> /dev/null)" || "${RECREATE_DATADIR}" == 'TRUE' ]]; then +# Do initialization if DATADIR directory is empty, or RECREATE_DATADIR is true +if [[ -z "$(ls -A ${DATADIR} 2> /dev/null)" || "${RECREATE_DATADIR}" =~ [Tt][Rr][Uu][Ee] ]]; then # Only attempt reinitializations if ${RECREATE_DATADIR} is true # No Replicate From settings. Assume that this is a master database. # Initialise db echo "Initializing Postgres Database at ${DATADIR}" - create_dir ${DATADIR} + create_dir "${DATADIR}" rm -rf ${DATADIR}/* - chown -R postgres:postgres ${DATADIR} + chown -R postgres:postgres "${DATADIR}" echo "Initializing with command:" - echo "postgres" > /tmp/superuser_pass.txt - command="$INITDB -U postgres --pwfile "/tmp/superuser_pass.txt" -E ${DEFAULT_ENCODING} --lc-collate=${DEFAULT_COLLATION} --lc-ctype=${DEFAULT_CTYPE} --wal-segsize=${WAL_SEGSIZE} --auth=${PASSWORD_AUTHENTICATION} -D ${DATADIR} ${INITDB_EXTRA_ARGS}" + command="$INITDB -U postgres --pwfile=<(echo "$POSTGRES_PASS") -E ${DEFAULT_ENCODING} --lc-collate=${DEFAULT_COLLATION} --lc-ctype=${DEFAULT_CTYPE} --wal-segsize=${WAL_SEGSIZE} --auth=${PASSWORD_AUTHENTICATION} -D ${DATADIR} ${INITDB_WALDIR_FLAG} ${INITDB_EXTRA_ARGS}" + echo "$command" su - postgres -c "$command" - rm /tmp/superuser_pass.txt +else + # If using existing datadir: + # Check if pg_wal symlink point to the correct directory described by POSTGRES_INITDB_WALDIR. + # Give warning if the value is not the same + if [[ -n "${POSTGRES_INITDB_WALDIR}" && \ + "$(realpath ${POSTGRES_INITDB_WALDIR})" != "$(realpath "$(readlink ${DATADIR}/pg_wal)")" ]]; then +cat << EOF 1>&2 +Warning! +POSTGRES_INITDB_WALDIR is not the same as what pg_wal is pointing to. +POSTGRES_INITDB_WALDIR: ${POSTGRES_INITDB_WALDIR} +pg_wal: $(readlink ${DATADIR}/pg_wal) +EOF + fi + + # Check if the pg_wal is empty. + # Exit the process if pg_wal is somehow empty + if [[ -z "$(ls -A ${DATADIR}/pg_wal 2> /dev/null)" ]]; then +cat << EOF 1>&2 +Error! +Can't proceed because "${DATADIR}/pg_wal" directory is empty. +EOF + exit 1 + fi fi; # Set proper permissions # needs to be done as root: -create_dir ${WAL_ARCHIVE} +create_dir "${WAL_ARCHIVE}" chown -R postgres:postgres ${DATADIR} ${WAL_ARCHIVE} chmod -R 750 ${DATADIR} ${WAL_ARCHIVE} @@ -44,8 +95,9 @@ source /scripts/setup-user.sh # enable extensions in template1 if env variable set to true if [[ "$(boolean ${POSTGRES_TEMPLATE_EXTENSIONS})" == TRUE ]] ; then for ext in $(echo ${POSTGRES_MULTIPLE_EXTENSIONS} | tr ',' ' '); do - echo "Enabling ${ext} in the database template1" - su - postgres -c "psql -c 'CREATE EXTENSION IF NOT EXISTS ${ext} cascade;' template1" + echo "Enabling \"${ext}\" in the database template1" + su - postgres -c "psql -c 'CREATE EXTENSION IF NOT EXISTS \"${ext}\" cascade;' template1" + su - postgres -c "psql -c 'CREATE EXTENSION IF NOT EXISTS tds_fdw;' template1" done fi @@ -53,17 +105,19 @@ fi # It will be owned by the docker db user # Since we now pass a comma separated list in database creation we need to search for all databases as a test + for db in $(echo ${POSTGRES_DBNAME} | tr ',' ' '); do RESULT=`su - postgres -c "psql -t -c \"SELECT count(1) from pg_database where datname='${db}';\""` + if [[ ${RESULT} -eq 0 ]]; then echo "Create db ${db}" su - postgres -c "createdb -O ${POSTGRES_USER} ${db}" for ext in $(echo ${POSTGRES_MULTIPLE_EXTENSIONS} | tr ',' ' '); do - echo "Enabling ${ext} in the database ${db}" + echo "Enabling \"${ext}\" in the database ${db}" if [[ ${ext} = 'pg_cron' ]]; then echo " pg_cron doesn't need to be installed" else - su - postgres -c "psql -c 'CREATE EXTENSION IF NOT EXISTS ${ext} cascade;' $db" + su - postgres -c "psql -c 'CREATE EXTENSION IF NOT EXISTS \"${ext}\" cascade;' $db" fi done echo "Loading legacy sql" @@ -79,6 +133,21 @@ for db in $(echo ${POSTGRES_DBNAME} | tr ',' ' '); do fi done +# Create schemas in the DB +for db in $(echo ${POSTGRES_DBNAME} | tr ',' ' '); do + for schema in $(echo ${SCHEMA_NAME} | tr ',' ' '); do + SCHEMA_RESULT=`PGPASSWORD=${POSTGRES_PASS} psql -t ${db} -U ${POSTGRES_USER} -p 5432 -h localhost -c "select count(1) from information_schema.schemata where schema_name = '${schemas}' and catalog_name = '${db}';"` + if [[ ${SCHEMA_RESULT} -eq 0 ]] && [[ "${ALL_DATABASES}" =~ [Ff][Aa][Ll][Ss][Ee] ]]; then + echo "Creating schema ${schema} in database ${SINGLE_DB}" + PGPASSWORD=${POSTGRES_PASS} psql ${SINGLE_DB} -U ${POSTGRES_USER} -p 5432 -h localhost -c " CREATE SCHEMA IF NOT EXISTS ${schema};" + elif [[ ${SCHEMA_RESULT} -eq 0 ]] && [[ "${ALL_DATABASES}" =~ [Tt][Rr][Uu][Ee] ]]; then + echo "Creating schema ${schema} in database ${db}" + PGPASSWORD=${POSTGRES_PASS} psql ${db} -U ${POSTGRES_USER} -p 5432 -h localhost -c " CREATE SCHEMA IF NOT EXISTS ${schema};" + fi + done +done + + CRON_LOCKFILE="${ROOT_CONF}/.cron_ext.lock" if [ ! -f "${CRON_LOCKFILE}" ]; then su - postgres -c "psql -c 'CREATE EXTENSION IF NOT EXISTS pg_cron cascade;' ${SINGLE_DB}" diff --git a/scripts/setup-pg_hba.sh b/scripts/setup-pg_hba.sh index fd2f0b5e..aaa146b0 100644 --- a/scripts/setup-pg_hba.sh +++ b/scripts/setup-pg_hba.sh @@ -7,24 +7,54 @@ if [ -f "${SETUP_LOCKFILE}" ]; then return 0 fi +# Setup Postgresql password +pg_password + # This script will setup pg_hba.conf # Reconfigure pg_hba if environment settings changed cat ${ROOT_CONF}/pg_hba.conf.template > ${ROOT_CONF}/pg_hba.conf + +if [[ "${FORCE_SSL}" =~ [Ff][Aa][Ll][Ss][Ee] ]]; then + PG_CONF_HOST='host' + CERT_AUTH=${PASSWORD_AUTHENTICATION} + CLIENT_VERIFY= +else + # If user has their own cert we default to force auth using cert method + if [[ "${SSL_KEY_FILE}" != '/etc/ssl/private/ssl-cert-snakeoil.key' ]]; then + PG_CONF_HOST='hostssl' + CERT_AUTH='cert' + CLIENT_VERIFY= + else + # Used when using the default ssl certs + PG_CONF_HOST='hostssl' + CERT_AUTH=${PASSWORD_AUTHENTICATION} + CLIENT_VERIFY='clientcert=0' + fi + +fi + +# Restrict subnet to docker private network +echo "$PG_CONF_HOST all all 172.0.0.0/8 ${CERT_AUTH} $CLIENT_VERIFY" >> $ROOT_CONF/pg_hba.conf +# And allow access from DockerToolbox / Boot to docker on OSX +echo "$PG_CONF_HOST all all 192.168.0.0/16 ${CERT_AUTH} $CLIENT_VERIFY" >> $ROOT_CONF/pg_hba.conf + # Custom IP range via docker run -e (https://docs.docker.com/engine/reference/run/#env-environment-variables) # Usage is: docker run [...] -e ALLOW_IP_RANGE='192.168.0.0/16' -if [[ "$ALLOW_IP_RANGE" ]] +if [[ -n "$ALLOW_IP_RANGE" ]] then echo "Add rule to pg_hba: $ALLOW_IP_RANGE" - echo "host all all $ALLOW_IP_RANGE ${PASSWORD_AUTHENTICATION}" >> ${ROOT_CONF}/pg_hba.conf + echo "$PG_CONF_HOST all all $ALLOW_IP_RANGE ${CERT_AUTH} $CLIENT_VERIFY" >> ${ROOT_CONF}/pg_hba.conf fi # check password first so we can output the warning before postgres # messes it up + if [[ "$POSTGRES_PASS" ]]; then pass="PASSWORD '$POSTGRES_PASS'" - authMethod=${PASSWORD_AUTHENTICATION} + authMethod=${CERT_AUTH} + else # The - option suppresses leading tabs but *not* spaces. :) cat >&2 <<-'EOWARN' @@ -49,7 +79,7 @@ if [[ -z "$REPLICATE_FROM" ]]; then # if env not set, then assume this is master instance # add rules to pg_hba.conf to allow replication from all echo "Add rule to pg_hba: replication ${REPLICATION_USER} " - echo "host replication ${REPLICATION_USER} ${ALLOW_IP_RANGE} $authMethod" >> ${ROOT_CONF}/pg_hba.conf + echo "$PG_CONF_HOST replication ${REPLICATION_USER} ${ALLOW_IP_RANGE} $authMethod $CLIENT_VERIFY" >> ${ROOT_CONF}/pg_hba.conf fi # Put lock file to make sure conf was not reinitialized diff --git a/scripts/setup-replication.sh b/scripts/setup-replication.sh index 02692950..cb5a09a2 100755 --- a/scripts/setup-replication.sh +++ b/scripts/setup-replication.sh @@ -7,37 +7,11 @@ source /scripts/env-data.sh # Adapted from https://github.com/DanielDent/docker-postgres-replication # To set up replication - - create_dir ${WAL_ARCHIVE} chown -R postgres:postgres ${DATADIR} ${WAL_ARCHIVE} chmod -R 750 ${DATADIR} ${WAL_ARCHIVE} - -function configure_replication_permissions { - - echo "Setup data permissions" - echo "----------------------" - chown -R postgres:postgres $(getent passwd postgres | cut -d: -f6) - su - postgres -c "echo \"${REPLICATE_FROM}:${REPLICATE_PORT}:*:${REPLICATION_USER}:${REPLICATION_PASS}\" > ~/.pgpass" - su - postgres -c "chmod 0600 ~/.pgpass" -} - -function streaming_replication { -until su - postgres -c "${PG_BASEBACKUP} -X stream -h ${REPLICATE_FROM} -p ${REPLICATE_PORT} -D ${DATADIR} -U ${REPLICATION_USER} -R -vP -w --label=gis_pg_custer" - do - echo "Waiting for master to connect..." - sleep 1s - if [[ "$(ls -A ${DATADIR})" ]]; then - echo "Need empty folder. Cleaning directory..." - rm -rf ${DATADIR}/* - fi - done - -} - - if [[ "$WAL_LEVEL" == 'replica' && "${REPLICATION}" =~ [Tt][Rr][Uu][Ee] ]]; then # No content yet - but this is a slave database if [ -z "${REPLICATE_FROM}" ]; then diff --git a/scripts/setup-ssl.sh b/scripts/setup-ssl.sh index 8ce2a6fe..116132e3 100644 --- a/scripts/setup-ssl.sh +++ b/scripts/setup-ssl.sh @@ -17,20 +17,30 @@ chown -R postgres /tmp/ssl-copy rm -r /etc/ssl mv /tmp/ssl-copy /etc/ssl -# Needed under debian, wasnt needed under ubuntu +# Setup Permission for SSL Directory +create_dir ${SSL_DIR} +chmod -R 0700 ${SSL_DIR} +chown -R postgres ${SSL_DIR} + +# Docker secrets for certificates +file_env 'SSL_CERT_FILE' +file_env 'SSL_KEY_FILE' +file_env 'SSL_CA_FILE' + +# Needed under debian, wasn't needed under ubuntu mkdir -p ${PGSTAT_TMP} chmod 0777 ${PGSTAT_TMP} # moved from setup.sh -echo "ssl = true" >> $CONF -#echo "ssl_ciphers = 'DEFAULT:!LOW:!EXP:!MD5:@STRENGTH' " >> $CONF -#echo "ssl_renegotiation_limit = 512MB " >> $CONF -echo "ssl_cert_file = '${SSL_CERT_FILE}'" >> $CONF -echo "ssl_key_file = '${SSL_KEY_FILE}'" >> $CONF +cat > ${ROOT_CONF}/ssl.conf <> $CONF + echo "ssl_ca_file = '${SSL_CA_FILE}' # (change requires restart)" >> ${ROOT_CONF}/ssl.conf fi -#echo "ssl_crl_file = ''" >> $CONF - +echo "include 'ssl.conf'" >> $CONF # Put lock file to make sure conf was not reinitialized touch ${SETUP_LOCKFILE} diff --git a/scripts/setup-user.sh b/scripts/setup-user.sh index 35b4d1c9..d296e3ff 100644 --- a/scripts/setup-user.sh +++ b/scripts/setup-user.sh @@ -14,9 +14,9 @@ source /scripts/env-data.sh # Only create credentials if this is a master database # Slave database will just mirror from master users -echo "Setup postgres User:Password" -echo "postgresql user: $POSTGRES_USER" > /tmp/PGPASSWORD.txt -echo "postgresql password: $POSTGRES_PASS" >> /tmp/PGPASSWORD.txt + + +POSTGRES_PASS=$(cat /tmp/PGPASSWORD.txt) # Check user already exists echo "Creating superuser $POSTGRES_USER" @@ -27,6 +27,9 @@ if [ -z "$RESULT" ]; then fi su - postgres -c "psql postgres -c \"$COMMAND USER $POSTGRES_USER WITH SUPERUSER ENCRYPTED PASSWORD '$POSTGRES_PASS';\"" +replication_password +REPLICATION_PASS=$(cat /tmp/REPLPASSWORD.txt) + echo "Creating replication user $REPLICATION_USER" RESULT_REPLICATION=`su - postgres -c "psql postgres -t -c \"SELECT 1 FROM pg_roles WHERE rolname = '$REPLICATION_USER'\""` COMMANDS="ALTER" diff --git a/scripts/setup-vpn.sh b/scripts/setup-vpn.sh new file mode 100644 index 00000000..85ec3815 --- /dev/null +++ b/scripts/setup-vpn.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +echo "Je suis le fichier openvpn." +# Verifiez que le fichier de configuration OpenVPN existe +if [ ! -f "/etc/openvpn/vpn.conf" ]; then + echo "Le fichier de configuration OpenVPN existe pas." + #exit 1 +fi +# Verifiez que le fichier de userpass existe +if [ ! -f "/etc/openvpn/userpass.txt" ]; then + echo "Le fichier userpass OpenVPN existe pas." + #exit 1 +fi +echo "Les fichier de configuration OpenVPN existent, je lance." +# Start OpenVPN +chmod 600 /etc/openvpn/userpass.txt +#openvpn --config /etc/openvpn/vpn.conf --cipher AES-256-GCM --verify-x509-name NONE --capath /etc/openvpn + +# Affichez un message de succès +echo "OpenVPN lancement fait" \ No newline at end of file diff --git a/scripts/setup.sh b/scripts/setup.sh index d64c2fde..3ec65b03 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -5,16 +5,6 @@ chmod 600 /etc/ssl/private/ssl-cert-snakeoil.key # These tasks are run as root source /scripts/env-data.sh - -# Restrict subnet to docker private network -echo "host all all 172.0.0.0/8 md5" >> $ROOT_CONF/pg_hba.conf -# And allow access from DockerToolbox / Boottodocker on OSX -echo "host all all 192.168.0.0/16 md5" >> $ROOT_CONF/pg_hba.conf -# Listen on all ip addresses -echo "listen_addresses = '*'" >> $CONF -echo "port = 5432" >> $CONF - - # Create backup template for conf cat $CONF > $CONF.template cat $ROOT_CONF/pg_hba.conf > $ROOT_CONF/pg_hba.conf.template diff --git a/userpass.txt b/userpass.txt new file mode 100644 index 00000000..72d57c12 --- /dev/null +++ b/userpass.txt @@ -0,0 +1,2 @@ +$VPN_USERNAME +$VPN_PASSWORD \ No newline at end of file diff --git a/vpn.conf b/vpn.conf new file mode 100644 index 00000000..9f8daaca --- /dev/null +++ b/vpn.conf @@ -0,0 +1,6 @@ +client +dev tun +proto tcp +port 443 +remote $VPN_HOST +auth-user-pass /etc/openvpn/userpass.txt \ No newline at end of file