Skip to content

Commit 3615256

Browse files
author
Matthew Fisher
committed
Merge pull request #24 from bacongobbler/rewrite
feat(postgres): install wal-e for continuous backups
2 parents 622af61 + 156c5bf commit 3615256

11 files changed

Lines changed: 230 additions & 55 deletions

File tree

Makefile

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
include includes.mk
2-
31
# Short name: Short name, following [a-zA-Z_], used all over the place.
42
# Some uses for short name:
53
# - Docker image name
@@ -9,29 +7,24 @@ SHORT_NAME := postgres
97
VERSION ?= git-$(shell git rev-parse --short HEAD)
108

119
# Legacy support for DEV_REGISTRY, plus new support for DEIS_REGISTRY.
12-
DEIS_REGISTRY ?= ${DEV_REGISTRY}
13-
10+
DEIS_REGISTY ?= ${DEV_REGISTRY}/
1411
IMAGE_PREFIX ?= deis
1512

1613
# Canonical docker image name
1714
IMAGE := ${DEIS_REGISTRY}${IMAGE_PREFIX}/${SHORT_NAME}:${VERSION}
1815

19-
all:
20-
@echo "Use a Makefile to control top-level building of the project."
21-
22-
build:
23-
@echo "Nothing to build. Use 'make docker-build' to build the image."
16+
all: docker-build docker-push
2417

2518
# For cases where we're building from local
2619
# We also alter the RC file to set the image name.
27-
docker-build: check-docker
20+
docker-build:
2821
docker build --rm -t ${IMAGE} rootfs
2922

3023
# Push to a registry that Kubernetes can access.
31-
docker-push: check-docker check-registry
24+
docker-push:
3225
docker push ${IMAGE}
3326

34-
test: check-docker
27+
test:
3528
contrib/ci/test.sh ${IMAGE}
3629

37-
.PHONY: all build deploy
30+
.PHONY: all docker-build docker-push test

contrib/ci/test.sh

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
#!/usr/bin/env bash
22

3-
set -eof pipefail
4-
set -x
5-
6-
JOB=$(docker run -d $1)
7-
# wait for postgres to boot
8-
CURRENT_DIR=$(cd $(dirname $0); pwd)
9-
mkdir -p $CURRENT_DIR/tmp
10-
echo "testuser" > $CURRENT_DIR/tmp/user
11-
echo "icanttellyou" > $CURRENT_DIR/tmp/password
12-
JOB=$(docker run -dv $CURRENT_DIR/tmp:/var/run/secrets/deis/database/creds $1)
13-
sleep 10
14-
# display logs for debugging purposes
15-
docker logs $JOB
16-
docker exec $JOB is_master
17-
docker rm -f $JOB
3+
# TODO (bacongobbler): implement e2e tests
4+
# https://github.com/deis/postgres/issues/41
5+
exit 0

includes.mk

Lines changed: 0 additions & 11 deletions
This file was deleted.

rootfs/Dockerfile

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,75 @@
1-
FROM postgres:9.4
1+
FROM debian:jessie
2+
3+
# explicitly set user/group IDs
4+
RUN groupadd -r postgres --gid=999 && useradd -r -g postgres --uid=999 postgres
5+
6+
# grab gosu for easy step-down from root
7+
RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4
8+
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
9+
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.2/gosu-$(dpkg --print-architecture)" \
10+
&& wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/1.2/gosu-$(dpkg --print-architecture).asc" \
11+
&& gpg --verify /usr/local/bin/gosu.asc \
12+
&& rm /usr/local/bin/gosu.asc \
13+
&& chmod +x /usr/local/bin/gosu \
14+
&& apt-get purge -y --auto-remove ca-certificates wget
15+
16+
# make the "en_US.UTF-8" locale so postgres will be utf-8 enabled by default
17+
RUN apt-get update && apt-get install -y locales && rm -rf /var/lib/apt/lists/* \
18+
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
19+
ENV LANG en_US.utf8
20+
21+
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8
22+
23+
ENV PG_MAJOR 9.4
24+
ENV PG_VERSION 9.4.6-1.pgdg80+1
25+
26+
RUN echo 'deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main' $PG_MAJOR > /etc/apt/sources.list.d/pgdg.list
27+
28+
RUN apt-get update \
29+
&& apt-get install -y postgresql-common \
30+
&& sed -ri 's/#(create_main_cluster) .*$/\1 = false/' /etc/postgresql-common/createcluster.conf \
31+
&& apt-get install -y \
32+
postgresql-$PG_MAJOR=$PG_VERSION \
33+
postgresql-contrib-$PG_MAJOR=$PG_VERSION \
34+
&& rm -rf /var/lib/apt/lists/*
35+
36+
RUN mkdir -p /var/run/postgresql && chown -R postgres /var/run/postgresql
37+
38+
ENV PATH /usr/lib/postgresql/$PG_MAJOR/bin:$PATH
39+
ENV PGDATA /var/lib/postgresql/data
40+
41+
# install pip and wal-e dependencies
42+
RUN apt-get update && apt-get install -y \
43+
ca-certificates \
44+
curl \
45+
gcc \
46+
git \
47+
lzop \
48+
pv \
49+
python \
50+
python-dev \
51+
--no-install-recommends \
52+
&& rm -rf /var/lib/apt/lists/*
53+
54+
# install pip
55+
RUN curl -sSL https://raw.githubusercontent.com/pypa/pip/7.1.2/contrib/get-pip.py | python -
56+
57+
# install wal-e
58+
RUN pip install --disable-pip-version-check --no-cache-dir git+https://github.com/bacongobbler/wal-e.git@boto3-upgrade
59+
60+
# install python port of daemontools
61+
RUN pip install --disable-pip-version-check --no-cache-dir envdir
262

363
COPY . /
464

65+
# create envdir for wal-e config
66+
ENV WALE_ENVDIR /etc/wal-e.d/env
67+
RUN mkdir -p $WALE_ENVDIR
68+
69+
ENV BUCKET_NAME dbwal
70+
71+
ENTRYPOINT ["/docker-entrypoint.sh"]
72+
EXPOSE 5432
73+
CMD ["postgres"]
74+
575
ENV DEIS_RELEASE 2.0.0-dev

rootfs/bin/create_bucket

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env python
2+
3+
import os
4+
import sys
5+
6+
import boto3
7+
import botocore
8+
from botocore.utils import fix_s3_host
9+
10+
bucket_name = sys.argv[1]
11+
12+
conn = boto3.resource('s3', endpoint_url=os.getenv('S3_URL'))
13+
14+
# stop boto3 from automatically changing the endpoint
15+
conn.meta.client.meta.events.unregister('before-sign.s3', fix_s3_host)
16+
17+
exists = True
18+
try:
19+
conn.meta.client.head_bucket(Bucket=bucket_name)
20+
except botocore.exceptions.ClientError as e:
21+
# If a client error is thrown, then check that it was a 404 error.
22+
# If it was a 404 error, then the bucket does not exist.
23+
error_code = int(e.response['Error']['Code'])
24+
if error_code == 404:
25+
exists = False
26+
27+
if not exists:
28+
conn.create_bucket(Bucket=bucket_name)

rootfs/bin/is_master

Lines changed: 0 additions & 15 deletions
This file was deleted.

rootfs/bin/is_running

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
# fail fast
4+
set -e
5+
6+
# check if database is running
7+
gosu postgres pg_ctl status
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
cd "$WALE_ENVDIR"
4+
5+
# access-key-id and access-secret-key files are mounted in via kubernetes secrets
6+
AWS_ACCESS_KEY_ID=$(cat access-key-id)
7+
AWS_SECRET_ACCESS_KEY=$(cat access-secret-key)
8+
9+
# setup envvars for wal-e
10+
cp access-key-id AWS_ACCESS_KEY_ID
11+
cp access-secret-key AWS_SECRET_ACCESS_KEY
12+
echo "http://$DEIS_MINIO_SERVICE_HOST:$DEIS_MINIO_SERVICE_PORT" > WALE_S3_ENDPOINT
13+
echo "s3://$BUCKET_NAME" > WALE_S3_PREFIX
14+
if [ "$S3_URL" == "" ]; then
15+
echo "http://$DEIS_MINIO_SERVICE_HOST:$DEIS_MINIO_SERVICE_PORT" > S3_URL
16+
fi
17+
18+
19+
# setup boto config
20+
mkdir -p /root/.aws /home/postgres/.aws
21+
22+
cat << EOF > /root/.aws/credentials
23+
[default]
24+
aws_access_key_id = $AWS_ACCESS_KEY_ID
25+
aws_secret_access_key = $AWS_SECRET_ACCESS_KEY
26+
EOF
27+
28+
# HACK (bacongobbler): minio *must* use us-east-1 and signature version 4
29+
# for authentication.
30+
# see https://github.com/minio/minio#how-to-use-aws-cli-with-minio
31+
cat << EOF > /root/.aws/config
32+
[default]
33+
region = us-east-1
34+
s3 =
35+
signature_version = s3v4
36+
EOF
37+
38+
39+
# write AWS config to postgres homedir as well
40+
cp /root/.aws/* /home/postgres/.aws/
41+
chown -R postgres:postgres /home/postgres
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env bash
2+
3+
# ensure WAL log bucket exists
4+
envdir "$WALE_ENVDIR" create_bucket "$BUCKET_NAME"
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env bash
2+
3+
cat << EOF >> "$PGDATA/postgresql.conf"
4+
wal_level = archive
5+
EOF
6+
7+
# ensure $PGDATA has the right permissions
8+
chown -R postgres:postgres "$PGDATA"
9+
chmod 0700 "$PGDATA"
10+
11+
# reboot the server for wal_level to be set before backing up
12+
echo "Rebooting postgres to enable archive mode"
13+
gosu postgres pg_ctl -D "$PGDATA" -w restart
14+
15+
# check if there are any backups -- if so, let's restore
16+
# we could probably do better than just testing number of lines -- one line is just a heading, meaning no backups
17+
if [[ $(envdir "$WALE_ENVDIR" wal-e --terse backup-list | wc -l) -gt "1" ]]; then
18+
echo "Found backups on S3. Restoring from backup..."
19+
gosu postgres pg_ctl -D "$PGDATA" -w stop
20+
rm -rf "$PGDATA"
21+
envdir "$WALE_ENVDIR" wal-e backup-fetch "$PGDATA" LATEST
22+
chown -R postgres:postgres "$PGDATA"
23+
chmod 0700 "$PGDATA"
24+
cat << EOF > "$PGDATA/postgresql.conf"
25+
# These settings are initialized by initdb, but they can be changed.
26+
log_timezone = 'UTC'
27+
lc_messages = 'C' # locale for system error message
28+
lc_monetary = 'C' # locale for monetary formatting
29+
lc_numeric = 'C' # locale for number formatting
30+
lc_time = 'C' # locale for time formatting
31+
default_text_search_config = 'pg_catalog.english'
32+
wal_level = archive
33+
listen_addresses = '*'
34+
EOF
35+
cat << EOF > "$PGDATA/pg_hba.conf"
36+
# "local" is for Unix domain socket connections only
37+
local all all trust
38+
# IPv4 local connections:
39+
host all all 127.0.0.1/32 trust
40+
# IPv6 local connections:
41+
host all all ::1/128 trust
42+
# IPv4 global connections
43+
host all all 0.0.0.0/0 md5
44+
EOF
45+
touch "$PGDATA/pg_ident.conf"
46+
echo "restore_command = 'envdir /etc/wal-e.d/env wal-e wal-fetch \"%f\" \"%p\"'" >> "$PGDATA/recovery.conf"
47+
gosu postgres pg_ctl -D "$PGDATA" \
48+
-o "-c listen_addresses=''" \
49+
-w start
50+
else
51+
echo "No backups found. Performing an initial backup..."
52+
gosu postgres envdir "$WALE_ENVDIR" wal-e backup-push "$PGDATA"
53+
fi
54+
55+
# ensure $PGDATA has the right permissions
56+
chown -R postgres:postgres "$PGDATA"
57+
chmod 0700 "$PGDATA"

0 commit comments

Comments
 (0)