├── .dockerignore ├── .gitignore ├── .gitmodules ├── .version ├── Dockerfile ├── LICENSE ├── README.md ├── bin ├── docker-cmd-coord ├── docker-cmd-data ├── docker-cmd-gtm ├── docker-cmd-proxy ├── docker-entrypoint-coord ├── docker-entrypoint-data ├── docker-entrypoint-gtm ├── docker-entrypoint-proxy ├── docker-healthcheck-coord ├── docker-healthcheck-data ├── docker-healthcheck-gtm ├── docker-healthcheck-proxy ├── docker-init-coord ├── docker-init-data ├── docker-init-gtm ├── docker-init-proxy ├── init-eg ├── init-eg-stack └── init-eg-swarm ├── ci ├── Dockerfile ├── meta.sh ├── meta.yml ├── package.sh ├── package.yml └── sh ├── docker-compose.image.yml ├── docker-compose.stack.yml └── docker-compose.yml /.dockerignore: -------------------------------------------------------------------------------- 1 | *.yml 2 | .*/ 3 | README.md 4 | bin/init-eg 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*.env 2 | /docker-compose.*.yml 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/postgres-xl"] 2 | path = lib/postgres-xl 3 | url = git://git.postgresql.org/git/postgres-xl.git 4 | -------------------------------------------------------------------------------- /.version: -------------------------------------------------------------------------------- 1 | XL_10_R1_1-313-g31dfe47 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #=============================================================================== 2 | # FROMFREEZE docker.io/library/debian:9 3 | FROM docker.io/library/debian@sha256:d844caef45253dab4cb7543b5781f529c1c3f140fcf9cd6172e1d6cb616a51c3 4 | 5 | ARG PG_HOME=/var/lib/postgresql 6 | ARG PG_LIB=/usr/local/lib/postgresql 7 | ARG PG_USER=postgres 8 | #------------------------------------------------------------------------------- 9 | RUN apt-get update && \ 10 | apt-get install -y --no-install-recommends \ 11 | bison \ 12 | build-essential \ 13 | daemontools \ 14 | flex \ 15 | libreadline-dev \ 16 | rsync \ 17 | netcat \ 18 | zlib1g-dev && \ 19 | rm -rf /var/lib/apt/lists/* 20 | 21 | RUN useradd ${PG_USER} -d ${PG_HOME} && \ 22 | mkdir -p ${PG_LIB} ${PG_HOME} && \ 23 | chown -R ${PG_USER}:${PG_USER} ${PG_LIB} ${PG_HOME} 24 | #------------------------------------------------------------------------------- 25 | WORKDIR ${PG_HOME} 26 | 27 | COPY --chown=postgres:postgres lib/ ./lib/ 28 | #------------------------------------------------------------------------------- 29 | USER ${PG_USER} 30 | 31 | WORKDIR ${PG_HOME}/lib/postgres-xl 32 | 33 | RUN ./configure --prefix ${PG_LIB} && \ 34 | make && \ 35 | cd contrib/pgxc_monitor && \ 36 | make 37 | #------------------------------------------------------------------------------- 38 | USER root 39 | 40 | RUN make install && \ 41 | cd contrib/pgxc_monitor && \ 42 | make install 43 | #------------------------------------------------------------------------------- 44 | USER ${PG_USER} 45 | 46 | WORKDIR ${PG_HOME} 47 | 48 | ENV PATH=${PG_LIB}/bin:$PATH \ 49 | PGDATA=${PG_HOME}/data \ 50 | PG_USER_HEALTHCHECK=_healthcheck 51 | 52 | COPY bin/* ${PG_LIB}/bin/ 53 | COPY ci/ ./ci/ 54 | 55 | VOLUME ${PG_HOME} 56 | #=============================================================================== 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2016-2020 Nic Williams , and other contributors (https://github.com/tiredpixel/postgres-xl-docker/graphs/contributors). 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Postgres-XL Docker 2 | 3 | [Postgres-XL Docker](https://github.com/tiredpixel/postgres-xl-docker) is a container image for [Postgres-XL](https://www.postgres-xl.org/), the scalable open-source [PostgreSQL](https://www.postgresql.org/)-based database cluster. 4 | 5 | The images allow for arbitrary database cluster topologies, allowing GTM, GTM Proxy, Coordinator, and Datanode nodes to be created and added as desired. Each service runs in its own container, communicating over a backend network. Coordinator nodes also connect to a frontend network. 6 | 7 | Previously, Postgres-XL Docker used `pgxc_ctl` for initialisation and control, running SSH servers as well as database services. This has now been completely redesigned to run database services directly without SSH, initialising using included helper scripts, and allowing full flexibility with regard to cluster topologies. The `pgxc_ctl` binary is no longer included in the image, since the recommended Postgres-XL Docker workflow is to *not* use it. 8 | 9 | 10 | ## Usage 11 | 12 | Instructions are for running on Docker using Docker Compose. It should be possible to boot an entire Postgres-XL cluster using these instructions. For running on Docker Swarm, you'll likely have to make minor tweaks. Please wave if something isn't clear or you have questions when doing this. 13 | 14 | It seems some people think that the way to use Postgres-XL Docker is to build it themselves from the Compose file. This is not the case; the images are published to Docker Hub, and those should normally be used instead. There's no need to compile this locally, unless you actually want to develop Postgres-XL Docker (or possibly Postgres-XL) itself. The supplied `docker-compose.image.yml` provides an example of how to do this; however, note that the `latest` tag is for testing and caching only; if you install a production database using `latest` or no tag at all, then you are doing it wrong, and your production will break at some point in the future. You have been warned. :) 15 | 16 | Note that the `pg_hba.conf` written is wide-open for any user on the backend network; if you use this method, be sure that you trust all users on that network, and isolate client connections using a frontend network. Alternatively, you might like to configure `ident` or `md5`, edit `pg_hba.conf` yourself, or not use the provided `init.sh` helper scripts. 17 | 18 | These instructions, along with the provided `docker-compose.yml` file, create: 19 | 20 | - 1 GTM (master) (`gtm_1`) 21 | - 2 Coordinators (master) (`coord_1`, `coord_2`) 22 | - 2 Datanodes (master) (`data_1`, `data_2`) 23 | 24 | ```txt 25 | -------------- 26 | | gtm_1 | 27 | -------------- 28 | / | | \ 29 | / | | \ 30 | / | | \ 31 | / | | \ 32 | / | | \ 33 | / | | \ 34 | / | | \ 35 | / | | \ 36 | / ------------ ------------ \ 37 | | | coord_1 | | coord_2 | | 38 | | ------------ ------------ | 39 | | / \ / \ | 40 | | / \/ \ | 41 | ------------ ------------/\------------ ------------ 42 | | data_1 | / \ | data_2 | 43 | ------------ ---- ---- ------------ 44 | ``` 45 | 46 | Other topologies are possible; you likely only need to edit `docker-compose.yml`, potentially setting additional environment variables. 47 | 48 | 49 | ## Build 50 | 51 | Clone repository. 52 | Pull source with `git submodule update --init --recursive`. 53 | Edit `docker-compose.yml` to reflect the desired topology. 54 | 55 | Build services by bringing them up. 56 | 57 | ```sh 58 | docker-compose up 59 | ``` 60 | 61 | This will create backend (`db_a`) and frontend (`db_b`) networks. 62 | 63 | 64 | ## Clustering (Automatically) 65 | 66 | Prepare an example cluster locally, using the provided example init script. This is not designed for production. Instead, configure by hand using whichever orchestrator you use, or write your own scripts. 67 | 68 | ```sh 69 | bin/init-eg 70 | ``` 71 | 72 | 73 | ## Clustering (Swarm; Automatically) 74 | 75 | If you're running on Docker Swarm, you can use the provided example `docker-compose.stack.yml` as a starting point, deploying with `docker stack deploy`, along with the init script. Note that the example makes various assumptions, such as that the Swarm node is a manager, that it is tagged with `grp=dbxl`, and that `db_a` has a lower subnet than `db_b` (which might or might not happen automatically; create the networks manually, if you're having trouble). 76 | 77 | ```sh 78 | bin/init-eg-swarm STACK_NAME 79 | ``` 80 | 81 | Note there are various caveats to using this, which you can read about in detail here: 82 | 83 | - https://github.com/tiredpixel/postgres-xl-docker/issues/27 84 | - https://github.com/tiredpixel/postgres-xl-docker/pull/28 85 | 86 | 87 | ## Clustering (Kubernetes; Automatically) 88 | 89 | Please keep in mind: 90 | 91 | 1. So as `docker stack` doesn't support `depends_on` option, it may cause errors until GTM node will be loaded. 92 | 2. Scripts below are using `kubectl` to execute commands on the K8s cluster. 93 | 94 | ```sh 95 | # TO UP 96 | docker stack deploy --orchestrator=kubernetes --namespace=default -c docker-compose.stack.yml pxl_stack 97 | # After you deployed pxl_stack, you need to initialize it (if it didn't do early or you purged PVC) 98 | ./bin/init-eg-stack 99 | 100 | # TO DOWN 101 | docker stack rm --orchestrator=kubernetes pxl_stack 102 | # Keep in mind that Persistent volumes (PVC) are NOT Docker volumes 103 | # If you want to purge that, you can to remove !!! ALL !!! PVC 👇 104 | kubectl delete pvc --all 105 | # To show all volumes use 👇 106 | kubectl get pv 107 | 108 | # TO PORT FORWARD 109 | kubectl port-forward 5432:5432 110 | # Also Kubernetes will make port-forwarding. You can find localhost port below 👇 111 | kubectl get service 112 | 113 | # TO GET INFO 114 | kubectl get all 115 | # or 116 | docker stack ps --orchestrator=kubernetes pxl_stack 117 | 118 | # TO GET LOGS 119 | kubectl describe pod db-data-2-0 120 | kubectl logs db-data-2-0 121 | 122 | # TO DEBUG 123 | kubectl exec db-gtm-1-0 -i -t -- bash -il 124 | # Where instead ☝️ db-gtm-1-0 may be used db-coord-1-0, db-coord-2-0, db-data-1-0, db-data-2-0 125 | # If you wanna run psql inside container, I suggest to add /usr/local/lib/postgresql/bin to $PATH var 126 | PATH=/usr/local/lib/postgresql/bin/:${PATH} 127 | ``` 128 | 129 | ### Pgpool 130 | 131 | Also you can add `pgpool` load balacer to the solution. It needs to make base enter point to database cluster and load balansing between coordinators. It sees cordinators nodes. For that: 132 | 133 | 1. Download `pgpool.conf` from [gist](https://gist.github.com/urpylka/4f3eeb0ec8d93e9f3ba7b700ad2dafe5). 134 | 2. Add these strings below to a `docker-compose` file 135 | 136 | ```docker-compose 137 | pgpool: 138 | image: smirart/pgpool:latest 139 | ports: 140 | - "5432:5432" 141 | volumes: 142 | - ./pgpool.conf:/etc/pgpool/pgpool.conf 143 | restart: always 144 | networks: 145 | - db-b 146 | ``` 147 | 148 | You can build [your own pgpool image](https://github.com/urpylka/docker-pgpool), otherwise use the prebuild image `smirart/pgpool:latest`. 149 | 150 | > As pgpool alternativity you can use `HAProxy`. 151 | 152 | ## Clustering (Manually) 153 | 154 | Prepare a clustering query, able to be executed on each node. Simplest is to use the same query for each node, open `psql` for each, and paste it into each. If you do this rather than crafting each line separately, expect some lines to error. 155 | 156 | On coordinators and datanodes: 157 | 158 | ```sql 159 | ALTER NODE data_1 WITH (TYPE = 'datanode'); 160 | ALTER NODE data_2 WITH (TYPE = 'datanode'); 161 | CREATE NODE coord_1 WITH (TYPE = 'coordinator', HOST = 'db_coord_1', PORT = 5432); 162 | CREATE NODE coord_2 WITH (TYPE = 'coordinator', HOST = 'db_coord_2', PORT = 5432); 163 | CREATE NODE data_1 WITH (TYPE = 'datanode', HOST = 'db_data_1', PORT = 5432); 164 | CREATE NODE data_2 WITH (TYPE = 'datanode', HOST = 'db_data_2', PORT = 5432); 165 | SELECT pgxc_pool_reload(); 166 | ``` 167 | 168 | The `ALTER` lines fix the datanodes to have the correct types within the cluster. The `CREATE` lines specify the cluster topology, but the line for the localhost will fail. The `pgxc_pool_reload()` reloads the configuration. 169 | 170 | Optionally, set preferred nodes. This could be a good idea if you've constrained nodes to run on specific hosts. For example, if you run `coord_1` and `data_1` on the same physical host, you might like to run this to ensure cross-network traffic is minimised. 171 | 172 | On `coord_1`: 173 | 174 | ```sql 175 | ALTER NODE data_1 WITH (PRIMARY, PREFERRED); 176 | SELECT pgxc_pool_reload(); 177 | ``` 178 | 179 | On `coord_2`: 180 | 181 | ```sql 182 | ALTER NODE data_2 WITH (PRIMARY, PREFERRED); 183 | SELECT pgxc_pool_reload(); 184 | ``` 185 | 186 | View the topologies on each node: 187 | 188 | ```sql 189 | SELECT * FROM pgxc_node; 190 | ``` 191 | 192 | 193 | ## Testing 194 | 195 | Test the cluster using the instructions provided in 196 | . 197 | 198 | For example, based on those instructions: 199 | 200 | On a coordinator: 201 | 202 | ```sql 203 | CREATE TABLE disttab (col1 int, col2 int, col3 text) DISTRIBUTE BY HASH(col1); 204 | \d+ disttab 205 | CREATE TABLE repltab (col1 int, col2 int) DISTRIBUTE BY REPLICATION; 206 | \d+ repltab 207 | INSERT INTO disttab SELECT generate_series(1, 100), generate_series(101, 200), 'foo'; 208 | INSERT INTO repltab SELECT generate_series(1, 100), generate_series(101, 200); 209 | SELECT count(*) FROM disttab; 210 | SELECT xc_node_id, count(*) FROM disttab GROUP BY xc_node_id; 211 | SELECT count(*) FROM repltab; 212 | SELECT xc_node_id, count(*) FROM repltab GROUP BY xc_node_id; 213 | ``` 214 | 215 | 216 | ## Blessing 217 | 218 | May you find peace, and help others to do likewise. 219 | 220 | 221 | ## Contact 222 | 223 | [tiredpixel.com](https://www.tiredpixel.com/) · [tp@tiredpixel.com](mailto:tp@tiredpixel.com) 224 | 225 | LinkedIn: [in/nic-williams](https://www.linkedin.com/in/nic-williams/) · Twitter: [tiredpixel](https://twitter.com/tiredpixel) · GitHub: [tiredpixel](https://github.com/tiredpixel) 226 | 227 | 228 | ## Licence 229 | 230 | Copyright © 2016-2020 [Nic Williams](https://www.tiredpixel.com/), and other [contributors](https://github.com/tiredpixel/postgres-xl-docker/graphs/contributors). It is free software, released under the MIT licence, and may be redistributed under the terms specified in `LICENSE`. 231 | -------------------------------------------------------------------------------- /bin/docker-cmd-coord: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | exec postgres \ 4 | -D "${PGDATA}" \ 5 | -h "${PG_HOST}" \ 6 | -p "${PG_PORT}" \ 7 | -c gtm_host="${PG_GTM_HOST}" \ 8 | -c gtm_port="${PG_GTM_PORT}" \ 9 | --coordinator 10 | -------------------------------------------------------------------------------- /bin/docker-cmd-data: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | exec postgres \ 4 | -D "${PGDATA}" \ 5 | -h "${PG_HOST}" \ 6 | -p "${PG_PORT}" \ 7 | -c gtm_host="${PG_GTM_HOST}" \ 8 | -c gtm_port="${PG_GTM_PORT}" \ 9 | --datanode 10 | -------------------------------------------------------------------------------- /bin/docker-cmd-gtm: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | exec gtm \ 4 | -D "${PGDATA}" \ 5 | -h "${PG_HOST}" \ 6 | -n "${PG_NODE}" \ 7 | -p "${PG_PORT}" \ 8 | -l /dev/stdout 9 | -------------------------------------------------------------------------------- /bin/docker-cmd-proxy: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | exec gtm_proxy \ 4 | -D "${PGDATA}" \ 5 | -h "${PG_HOST}" \ 6 | -p "${PG_PORT}" \ 7 | -i "${PG_NODE}" \ 8 | -s "${PG_GTM_HOST}" \ 9 | -t "${PG_GTM_PORT}" \ 10 | -l /dev/stdout 11 | -------------------------------------------------------------------------------- /bin/docker-entrypoint-coord: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | test -d "$PGDATA" || docker-init-coord 4 | 5 | exec "$@" 6 | -------------------------------------------------------------------------------- /bin/docker-entrypoint-data: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | test -d "$PGDATA" || docker-init-data 4 | 5 | exec "$@" 6 | -------------------------------------------------------------------------------- /bin/docker-entrypoint-gtm: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | test -d "$PGDATA" || docker-init-gtm 4 | 5 | exec "$@" 6 | -------------------------------------------------------------------------------- /bin/docker-entrypoint-proxy: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | test -d "$PGDATA" || docker-init-proxy 4 | 5 | exec "$@" 6 | -------------------------------------------------------------------------------- /bin/docker-healthcheck-coord: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | bootstrapped=.bootstrapped 4 | sleep_int_max=30 5 | #------------------------------------------------------------------------------- 6 | if [ ! -f "$bootstrapped" ]; then 7 | sleep_int=$(((RANDOM % sleep_int_max) + 1)) 8 | echo "Sleeping to avoid race-condition (!) [$sleep_int s]" 9 | sleep "$sleep_int" 10 | 11 | createuser \ 12 | -h "${PG_HOST}" \ 13 | -p "${PG_PORT}" \ 14 | "${PG_USER_HEALTHCHECK}" || true 15 | 16 | createdb \ 17 | -h "${PG_HOST}" \ 18 | -p "${PG_PORT}" \ 19 | -O "${PG_USER_HEALTHCHECK}" \ 20 | "${PG_USER_HEALTHCHECK}" || true 21 | 22 | psql \ 23 | -h "${PG_HOST}" \ 24 | -p "${PG_PORT}" \ 25 | -U "${PG_USER_HEALTHCHECK}" \ 26 | -d "${PG_USER_HEALTHCHECK}" \ 27 | -c 'CREATE TABLE ping (t_ins timestamptz NOT NULL DEFAULT now())' || 28 | true 29 | fi 30 | 31 | ( 32 | psql \ 33 | -h "${PG_HOST}" \ 34 | -p "${PG_PORT}" \ 35 | -U "${PG_USER_HEALTHCHECK}" \ 36 | -d "${PG_USER_HEALTHCHECK}" \ 37 | -c 'INSERT INTO ping VALUES (DEFAULT)' && 38 | touch "$bootstrapped" 39 | ) || 40 | [ ! -f "$bootstrapped" ] 41 | -------------------------------------------------------------------------------- /bin/docker-healthcheck-data: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | bootstrapped=.bootstrapped 4 | 5 | ( 6 | psql \ 7 | -h "${PG_HOST}" \ 8 | -p "${PG_PORT}" \ 9 | -U "${PG_USER_HEALTHCHECK}" \ 10 | -c 'SELECT version()' && 11 | touch "$bootstrapped" 12 | ) || 13 | [ ! -f "$bootstrapped" ] 14 | -------------------------------------------------------------------------------- /bin/docker-healthcheck-gtm: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | pgxc_monitor -Z gtm -h "${PG_HOST}" -p "${PG_PORT}" 4 | -------------------------------------------------------------------------------- /bin/docker-healthcheck-proxy: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | # UNIMPLEMENTED 4 | exit 0 5 | -------------------------------------------------------------------------------- /bin/docker-init-coord: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | initdb \ 4 | -D "${PGDATA}" \ 5 | --nodename="${PG_NODE}" 6 | 7 | nets=($(ip -o -f inet addr show | awk '/scope global/ {print $4}' | 8 | sort -V | xargs)) 9 | 10 | echo "pg_hba: adding host trust ${nets[0]}" 11 | 12 | echo "host all all ${nets[0]} trust" >> \ 13 | "${PGDATA}/pg_hba.conf" 14 | 15 | echo "pg_hba: adding host md5 ${nets[1]}" 16 | 17 | echo "host all all ${nets[1]} md5" >> \ 18 | "${PGDATA}/pg_hba.conf" 19 | -------------------------------------------------------------------------------- /bin/docker-init-data: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | initdb \ 4 | -D "${PGDATA}" \ 5 | --nodename="${PG_NODE}" 6 | 7 | nets=($(ip -o -f inet addr show | awk '/scope global/ {print $4}' | 8 | sort -V | xargs)) 9 | 10 | echo "pg_hba: adding host trust ${nets[0]}" 11 | 12 | echo "host all all ${nets[0]} trust" >> \ 13 | "${PGDATA}/pg_hba.conf" 14 | -------------------------------------------------------------------------------- /bin/docker-init-gtm: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | initgtm \ 4 | -D "${PGDATA}" \ 5 | -Z gtm 6 | -------------------------------------------------------------------------------- /bin/docker-init-proxy: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | initgtm \ 4 | -D "${PGDATA}" \ 5 | -Z gtm_proxy 6 | -------------------------------------------------------------------------------- /bin/init-eg: -------------------------------------------------------------------------------- 1 | #!/bin/bash -u 2 | 3 | nodes=(db_coord_1 db_coord_2 db_data_1 db_data_2) 4 | #------------------------------------------------------------------------------- 5 | function log() { 6 | local msg="$*" 7 | 8 | echo "$(date -u '+%Y-%m-%dT%H:%M:%S%z'), $msg" 9 | } 10 | 11 | function startup() { 12 | log "========================================" 13 | } 14 | 15 | function shutdown() { 16 | log "----------------------------------------" 17 | } 18 | 19 | function srv() { 20 | local node=$1 21 | shift 22 | 23 | docker-compose exec "$node" "$@" 24 | } 25 | 26 | function cmd() { 27 | local node=$1 28 | shift 29 | 30 | log "$@" 31 | srv "$node" psql -c "$@" 32 | } 33 | 34 | trap shutdown EXIT 35 | #------------------------------------------------------------------------------- 36 | startup 37 | 38 | for node in "${nodes[@]}" 39 | do 40 | cmd "$node" "CREATE NODE coord_1 WITH (TYPE = 'coordinator', HOST = 'db_coord_1', PORT = 5432);" 41 | cmd "$node" "CREATE NODE coord_2 WITH (TYPE = 'coordinator', HOST = 'db_coord_2', PORT = 5432);" 42 | cmd "$node" "CREATE NODE data_1 WITH (TYPE = 'datanode', HOST = 'db_data_1', PORT = 5432);" 43 | cmd "$node" "CREATE NODE data_2 WITH (TYPE = 'datanode', HOST = 'db_data_2', PORT = 5432);" 44 | 45 | cmd "$node" "ALTER NODE coord_1 WITH (TYPE = 'coordinator', HOST = 'db_coord_1', PORT = 5432);" 46 | cmd "$node" "ALTER NODE coord_2 WITH (TYPE = 'coordinator', HOST = 'db_coord_2', PORT = 5432);" 47 | cmd "$node" "ALTER NODE data_1 WITH (TYPE = 'datanode', HOST = 'db_data_1', PORT = 5432);" 48 | cmd "$node" "ALTER NODE data_2 WITH (TYPE = 'datanode', HOST = 'db_data_2', PORT = 5432);" 49 | 50 | cmd "$node" "SELECT pgxc_pool_reload();" 51 | cmd "$node" "SELECT * FROM pgxc_node;" 52 | done 53 | -------------------------------------------------------------------------------- /bin/init-eg-stack: -------------------------------------------------------------------------------- 1 | #!/bin/bash -u 2 | 3 | nodes=(db-coord-1 db-coord-2 db-data-1 db-data-2) 4 | #------------------------------------------------------------------------------- 5 | function log() { 6 | local msg="$*" 7 | 8 | echo "$(date -u '+%Y-%m-%dT%H:%M:%S%z'), $msg" 9 | } 10 | 11 | function startup() { 12 | log "========================================" 13 | } 14 | 15 | function shutdown() { 16 | log "----------------------------------------" 17 | } 18 | 19 | function srv() { 20 | local node=$1 21 | shift 22 | 23 | kubectl exec "$node" -i -t -- "$@" 24 | } 25 | 26 | function cmd() { 27 | local node=$1 28 | shift 29 | 30 | log "$@" 31 | srv "$node" psql -c "$@" 32 | } 33 | 34 | function get_container() { 35 | local node=$1 36 | 37 | id="0" 38 | echo "${node}-${id}" 39 | } 40 | 41 | trap shutdown EXIT 42 | #------------------------------------------------------------------------------- 43 | startup 44 | 45 | for node in "${nodes[@]}" 46 | do 47 | ctnr=$(get_container "$node") 48 | 49 | cmd "$ctnr" "CREATE NODE coord_1 WITH (TYPE = 'coordinator', HOST = 'db-coord-1', PORT = 5432);" 50 | cmd "$ctnr" "CREATE NODE coord_2 WITH (TYPE = 'coordinator', HOST = 'db-coord-2', PORT = 5432);" 51 | cmd "$ctnr" "CREATE NODE data_1 WITH (TYPE = 'datanode', HOST = 'db-data-1', PORT = 5432);" 52 | cmd "$ctnr" "CREATE NODE data_2 WITH (TYPE = 'datanode', HOST = 'db-data-2', PORT = 5432);" 53 | cmd "$ctnr" "ALTER NODE coord_1 WITH (TYPE = 'coordinator', HOST = 'db-coord-1', PORT = 5432);" 54 | cmd "$ctnr" "ALTER NODE coord_2 WITH (TYPE = 'coordinator', HOST = 'db-coord-2', PORT = 5432);" 55 | cmd "$ctnr" "ALTER NODE data_1 WITH (TYPE = 'datanode', HOST = 'db-data-1', PORT = 5432);" 56 | cmd "$ctnr" "ALTER NODE data_2 WITH (TYPE = 'datanode', HOST = 'db-data-2', PORT = 5432);" 57 | cmd "$ctnr" "SELECT pgxc_pool_reload();" 58 | cmd "$ctnr" "SELECT * FROM pgxc_node;" 59 | done 60 | -------------------------------------------------------------------------------- /bin/init-eg-swarm: -------------------------------------------------------------------------------- 1 | #!/bin/bash -u 2 | 3 | stack=$1 4 | 5 | nodes=(db_coord_1 db_coord_2 db_data_1 db_data_2) 6 | #------------------------------------------------------------------------------- 7 | function log() { 8 | local msg="$*" 9 | 10 | echo "$(date -u '+%Y-%m-%dT%H:%M:%S%z'), $msg" 11 | } 12 | 13 | function startup() { 14 | log "========================================" 15 | } 16 | 17 | function shutdown() { 18 | log "----------------------------------------" 19 | } 20 | 21 | function srv() { 22 | local node=$1 23 | shift 24 | 25 | docker exec "$node" "$@" 26 | } 27 | 28 | function cmd() { 29 | local node=$1 30 | shift 31 | 32 | log "$@" 33 | srv "$node" psql -c "$@" 34 | } 35 | 36 | function get_container() { 37 | local node=$1 38 | 39 | id=$(docker service ps -f 'desired-state=running' -q "${stack}_${node}" | 40 | head -n1) 41 | echo "${stack}_${node}.1.${id}" 42 | } 43 | 44 | trap shutdown EXIT 45 | #------------------------------------------------------------------------------- 46 | startup 47 | 48 | for node in "${nodes[@]}" 49 | do 50 | ctnr=$(get_container "$node") 51 | 52 | cmd "$ctnr" "CREATE NODE coord_1 WITH (TYPE = 'coordinator', HOST = 'db_coord_1', PORT = 5432);" 53 | cmd "$ctnr" "CREATE NODE coord_2 WITH (TYPE = 'coordinator', HOST = 'db_coord_2', PORT = 5432);" 54 | cmd "$ctnr" "CREATE NODE data_1 WITH (TYPE = 'datanode', HOST = 'db_data_1', PORT = 5432);" 55 | cmd "$ctnr" "CREATE NODE data_2 WITH (TYPE = 'datanode', HOST = 'db_data_2', PORT = 5432);" 56 | cmd "$ctnr" "ALTER NODE coord_1 WITH (TYPE = 'coordinator', HOST = 'db_coord_1', PORT = 5432);" 57 | cmd "$ctnr" "ALTER NODE coord_2 WITH (TYPE = 'coordinator', HOST = 'db_coord_2', PORT = 5432);" 58 | cmd "$ctnr" "ALTER NODE data_1 WITH (TYPE = 'datanode', HOST = 'db_data_1', PORT = 5432);" 59 | cmd "$ctnr" "ALTER NODE data_2 WITH (TYPE = 'datanode', HOST = 'db_data_2', PORT = 5432);" 60 | cmd "$ctnr" "SELECT pgxc_pool_reload();" 61 | cmd "$ctnr" "SELECT * FROM pgxc_node;" 62 | done 63 | -------------------------------------------------------------------------------- /ci/Dockerfile: -------------------------------------------------------------------------------- 1 | #=============================================================================== 2 | # FROMFREEZE docker.io/library/debian:9 3 | FROM docker.io/library/debian@sha256:d844caef45253dab4cb7543b5781f529c1c3f140fcf9cd6172e1d6cb616a51c3 4 | 5 | ARG PG_HOME=/var/lib/postgresql 6 | ARG PG_LIB=/usr/local/lib/postgresql 7 | ARG PG_USER=postgres 8 | #------------------------------------------------------------------------------- 9 | RUN apt-get update && \ 10 | apt-get install -y --no-install-recommends \ 11 | libreadline-dev \ 12 | rsync \ 13 | netcat && \ 14 | rm -rf /var/lib/apt/lists/* 15 | 16 | RUN useradd ${PG_USER} -d ${PG_HOME} && \ 17 | mkdir -p ${PG_LIB} ${PG_HOME} && \ 18 | chown -R ${PG_USER}:${PG_USER} ${PG_LIB} ${PG_HOME} 19 | #------------------------------------------------------------------------------- 20 | USER ${PG_USER} 21 | 22 | WORKDIR ${PG_HOME} 23 | 24 | ENV PATH=${PG_LIB}/bin:$PATH \ 25 | PGDATA=${PG_HOME}/data \ 26 | PG_USER_HEALTHCHECK=_healthcheck 27 | 28 | COPY postgresql ${PG_LIB} 29 | 30 | VOLUME ${PG_HOME} 31 | #=============================================================================== 32 | -------------------------------------------------------------------------------- /ci/meta.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | set -o pipefail 3 | 4 | src=$PWD/src 5 | meta=$PWD/meta 6 | 7 | test -d "$meta" || meta=$(mktemp -d) 8 | #------------------------------------------------------------------------------- 9 | cd "$src" 10 | 11 | version=$(git describe) 12 | 13 | echo -n "$version" > "$meta/version" 14 | touch "$meta/tags" 15 | 16 | release=$(git describe --abbrev=0) 17 | 18 | if [ "$version" == "$release" ]; then 19 | release_1=$(echo "$release" | cut -d'.' -f1) 20 | release_2=$(echo "$release" | cut -d'.' -f2) 21 | 22 | # release tagged for completeness, but version same 23 | echo -n "$release $release_1.$release_2 $release_1 " >> "$meta/tags" 24 | fi 25 | 26 | commit_latest=$(git for-each-ref --sort=-committerdate --format="%(objectname)" refs/remotes/ | head -n1) 27 | commit_head=$(git rev-parse HEAD) 28 | 29 | if [ "$commit_head" == "$commit_latest" ]; then 30 | echo -n "latest " >> "$meta/tags" 31 | fi 32 | #------------------------------------------------------------------------------- 33 | echo "version: $(cat "$meta/version")" 34 | echo "tags: $(cat "$meta/tags")" 35 | -------------------------------------------------------------------------------- /ci/meta.yml: -------------------------------------------------------------------------------- 1 | platform: linux 2 | image_resource: 3 | type: docker-image 4 | source: 5 | repository: concourse/buildroot 6 | tag: git 7 | inputs: 8 | - name: src 9 | outputs: 10 | - name: meta 11 | run: 12 | path: src/ci/meta.sh 13 | -------------------------------------------------------------------------------- /ci/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | src=/var/lib/postgresql 4 | pkg=$PWD/pkg 5 | postgresql=/usr/local/lib/postgresql 6 | 7 | cd "$src" 8 | cp ci/Dockerfile "$pkg/" 9 | cp -R "$postgresql" "$pkg/postgresql/" 10 | 11 | ls -AlhR "$pkg" 12 | -------------------------------------------------------------------------------- /ci/package.yml: -------------------------------------------------------------------------------- 1 | platform: linux 2 | inputs: 3 | - name: src 4 | outputs: 5 | - name: pkg 6 | run: 7 | user: root 8 | path: src/ci/sh 9 | args: 10 | - src/ci/package.sh 11 | -------------------------------------------------------------------------------- /ci/sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | USER=postgres 4 | 5 | chown -R ${USER}:root /tmp/build 6 | 7 | setuidgid ${USER} "$@" 8 | -------------------------------------------------------------------------------- /docker-compose.image.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | x-custom: 3 | shared_image: &shared_image 4 | image: pavouk0/postgres-xl:XL_10_R1_1-313-g31dfe47-13-gbe4dce7 5 | services: 6 | db_gtm_1: 7 | environment: 8 | - PG_HOST=0.0.0.0 9 | - PG_NODE=gtm_1 10 | - PG_PORT=6666 11 | <<: *shared_image 12 | command: docker-cmd-gtm 13 | entrypoint: docker-entrypoint-gtm 14 | volumes: 15 | - db_gtm_1:/var/lib/postgresql 16 | networks: 17 | - db_a 18 | healthcheck: 19 | test: ["CMD", "docker-healthcheck-gtm"] 20 | db_coord_1: 21 | environment: 22 | - PG_GTM_HOST=db_gtm_1 23 | - PG_GTM_PORT=6666 24 | - PG_HOST=0.0.0.0 25 | - PG_NODE=coord_1 26 | - PG_PORT=5432 27 | <<: *shared_image 28 | command: docker-cmd-coord 29 | entrypoint: docker-entrypoint-coord 30 | volumes: 31 | - db_coord_1:/var/lib/postgresql 32 | depends_on: 33 | - db_gtm_1 34 | networks: 35 | - db_a 36 | - db_b 37 | healthcheck: 38 | test: ["CMD", "docker-healthcheck-coord"] 39 | db_coord_2: 40 | environment: 41 | - PG_GTM_HOST=db_gtm_1 42 | - PG_GTM_PORT=6666 43 | - PG_HOST=0.0.0.0 44 | - PG_NODE=coord_2 45 | - PG_PORT=5432 46 | <<: *shared_image 47 | command: docker-cmd-coord 48 | entrypoint: docker-entrypoint-coord 49 | volumes: 50 | - db_coord_2:/var/lib/postgresql 51 | depends_on: 52 | - db_gtm_1 53 | networks: 54 | - db_a 55 | - db_b 56 | healthcheck: 57 | test: ["CMD", "docker-healthcheck-coord"] 58 | db_data_1: 59 | environment: 60 | - PG_GTM_HOST=db_gtm_1 61 | - PG_GTM_PORT=6666 62 | - PG_HOST=0.0.0.0 63 | - PG_NODE=data_1 64 | - PG_PORT=5432 65 | <<: *shared_image 66 | command: docker-cmd-data 67 | entrypoint: docker-entrypoint-data 68 | depends_on: 69 | - db_gtm_1 70 | volumes: 71 | - db_data_1:/var/lib/postgresql 72 | networks: 73 | - db_a 74 | healthcheck: 75 | test: ["CMD", "docker-healthcheck-data"] 76 | db_data_2: 77 | environment: 78 | - PG_GTM_HOST=db_gtm_1 79 | - PG_GTM_PORT=6666 80 | - PG_HOST=0.0.0.0 81 | - PG_NODE=data_2 82 | - PG_PORT=5432 83 | <<: *shared_image 84 | command: docker-cmd-data 85 | entrypoint: docker-entrypoint-data 86 | depends_on: 87 | - db_gtm_1 88 | volumes: 89 | - db_data_2:/var/lib/postgresql 90 | networks: 91 | - db_a 92 | healthcheck: 93 | test: ["CMD", "docker-healthcheck-data"] 94 | volumes: 95 | db_gtm_1: {} 96 | db_coord_1: {} 97 | db_coord_2: {} 98 | db_data_1: {} 99 | db_data_2: {} 100 | networks: 101 | db_a: 102 | internal: true 103 | db_b: 104 | internal: true 105 | -------------------------------------------------------------------------------- /docker-compose.stack.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | x-custom: 4 | shared_image: &shared_image 5 | image: pavouk0/postgres-xl:XL_10_R1_1-313-g31dfe47 6 | 7 | services: 8 | db-gtm-1: 9 | <<: *shared_image 10 | environment: 11 | - PG_HOST=0.0.0.0 12 | - PG_NODE=gtm_1 13 | - PG_PORT=6666 14 | command: docker-cmd-gtm 15 | entrypoint: docker-entrypoint-gtm 16 | volumes: 17 | - db-gtm-1:/var/lib/postgresql 18 | networks: 19 | - db_a 20 | healthcheck: 21 | test: ["CMD", "docker-healthcheck-gtm"] 22 | interval: 30s 23 | timeout: 30s 24 | start_period: 0s 25 | retries: 3 26 | # deploy: 27 | # placement: 28 | # constraints: 29 | # - node.labels.grp == dbxl # assumes shared volume storage, or 1-node 30 | db-coord-1: 31 | <<: *shared_image 32 | environment: 33 | - PG_GTM_HOST=db-gtm-1 34 | - PG_GTM_PORT=6666 35 | - PG_HOST=0.0.0.0 36 | - PG_NODE=coord_1 37 | - PG_PORT=5432 38 | command: docker-cmd-coord 39 | entrypoint: docker-entrypoint-coord 40 | volumes: 41 | - db-coord-1:/var/lib/postgresql 42 | networks: 43 | - db_a 44 | - db_b 45 | healthcheck: 46 | test: ["CMD", "docker-healthcheck-coord"] 47 | interval: 30s 48 | timeout: 30s 49 | start_period: 0s 50 | retries: 3 51 | # deploy: 52 | # placement: 53 | # constraints: 54 | # - node.labels.grp == dbxl # assumes shared volume storage, or 1-node 55 | db-coord-2: 56 | <<: *shared_image 57 | environment: 58 | - PG_GTM_HOST=db-gtm-1 59 | - PG_GTM_PORT=6666 60 | - PG_HOST=0.0.0.0 61 | - PG_NODE=coord_2 62 | - PG_PORT=5432 63 | command: docker-cmd-coord 64 | entrypoint: docker-entrypoint-coord 65 | volumes: 66 | - db-coord-2:/var/lib/postgresql 67 | networks: 68 | - db_a 69 | - db_b 70 | healthcheck: 71 | test: ["CMD", "docker-healthcheck-coord"] 72 | interval: 30s 73 | timeout: 30s 74 | start_period: 0s 75 | retries: 3 76 | # deploy: 77 | # placement: 78 | # constraints: 79 | # - node.labels.grp == dbxl # assumes shared volume storage, or 1-node 80 | db-data-1: 81 | <<: *shared_image 82 | environment: 83 | - PG_GTM_HOST=db-gtm-1 84 | - PG_GTM_PORT=6666 85 | - PG_HOST=0.0.0.0 86 | - PG_NODE=data_1 87 | - PG_PORT=5432 88 | command: docker-cmd-data 89 | entrypoint: docker-entrypoint-data 90 | volumes: 91 | - db-data-1:/var/lib/postgresql 92 | networks: 93 | - db_a 94 | healthcheck: 95 | test: ["CMD", "docker-healthcheck-data"] 96 | interval: 30s 97 | timeout: 30s 98 | start_period: 0s 99 | retries: 3 100 | # deploy: 101 | # placement: 102 | # constraints: 103 | # - node.labels.grp == dbxl # assumes shared volume storage, or 1-node 104 | db-data-2: 105 | <<: *shared_image 106 | environment: 107 | - PG_GTM_HOST=db-gtm-1 108 | - PG_GTM_PORT=6666 109 | - PG_HOST=0.0.0.0 110 | - PG_NODE=data_2 111 | - PG_PORT=5432 112 | command: docker-cmd-data 113 | entrypoint: docker-entrypoint-data 114 | volumes: 115 | - db-data-2:/var/lib/postgresql 116 | networks: 117 | - db_a 118 | healthcheck: 119 | test: ["CMD", "docker-healthcheck-data"] 120 | interval: 30s 121 | timeout: 30s 122 | start_period: 0s 123 | retries: 3 124 | # deploy: 125 | # placement: 126 | # constraints: 127 | # - node.labels.grp == dbxl # assumes shared volume storage, or 1-node 128 | 129 | volumes: 130 | db-gtm-1: {} 131 | db-coord-1: {} 132 | db-coord-2: {} 133 | db-data-1: {} 134 | db-data-2: {} 135 | 136 | networks: 137 | db_a: 138 | driver: overlay 139 | internal: true 140 | db_b: 141 | driver: overlay 142 | internal: true 143 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | db_gtm_1: 4 | environment: 5 | - PG_HOST=0.0.0.0 6 | - PG_NODE=gtm_1 7 | - PG_PORT=6666 8 | build: . 9 | command: docker-cmd-gtm 10 | entrypoint: docker-entrypoint-gtm 11 | volumes: 12 | - db_gtm_1:/var/lib/postgresql 13 | networks: 14 | - db_a 15 | healthcheck: 16 | test: ["CMD", "docker-healthcheck-gtm"] 17 | db_coord_1: 18 | environment: 19 | - PG_GTM_HOST=db_gtm_1 20 | - PG_GTM_PORT=6666 21 | - PG_HOST=0.0.0.0 22 | - PG_NODE=coord_1 23 | - PG_PORT=5432 24 | build: . 25 | command: docker-cmd-coord 26 | entrypoint: docker-entrypoint-coord 27 | volumes: 28 | - db_coord_1:/var/lib/postgresql 29 | depends_on: 30 | - db_gtm_1 31 | networks: 32 | - db_a 33 | - db_b 34 | healthcheck: 35 | test: ["CMD", "docker-healthcheck-coord"] 36 | db_coord_2: 37 | environment: 38 | - PG_GTM_HOST=db_gtm_1 39 | - PG_GTM_PORT=6666 40 | - PG_HOST=0.0.0.0 41 | - PG_NODE=coord_2 42 | - PG_PORT=5432 43 | build: . 44 | command: docker-cmd-coord 45 | entrypoint: docker-entrypoint-coord 46 | volumes: 47 | - db_coord_2:/var/lib/postgresql 48 | depends_on: 49 | - db_gtm_1 50 | networks: 51 | - db_a 52 | - db_b 53 | healthcheck: 54 | test: ["CMD", "docker-healthcheck-coord"] 55 | db_data_1: 56 | environment: 57 | - PG_GTM_HOST=db_gtm_1 58 | - PG_GTM_PORT=6666 59 | - PG_HOST=0.0.0.0 60 | - PG_NODE=data_1 61 | - PG_PORT=5432 62 | build: . 63 | command: docker-cmd-data 64 | entrypoint: docker-entrypoint-data 65 | depends_on: 66 | - db_gtm_1 67 | volumes: 68 | - db_data_1:/var/lib/postgresql 69 | networks: 70 | - db_a 71 | healthcheck: 72 | test: ["CMD", "docker-healthcheck-data"] 73 | db_data_2: 74 | environment: 75 | - PG_GTM_HOST=db_gtm_1 76 | - PG_GTM_PORT=6666 77 | - PG_HOST=0.0.0.0 78 | - PG_NODE=data_2 79 | - PG_PORT=5432 80 | build: . 81 | command: docker-cmd-data 82 | entrypoint: docker-entrypoint-data 83 | depends_on: 84 | - db_gtm_1 85 | volumes: 86 | - db_data_2:/var/lib/postgresql 87 | networks: 88 | - db_a 89 | healthcheck: 90 | test: ["CMD", "docker-healthcheck-data"] 91 | volumes: 92 | db_gtm_1: {} 93 | db_coord_1: {} 94 | db_coord_2: {} 95 | db_data_1: {} 96 | db_data_2: {} 97 | networks: 98 | db_a: 99 | internal: true 100 | db_b: 101 | internal: true 102 | --------------------------------------------------------------------------------