说明:
不使用docker hub上的offical postgresql镜像,有几个原因:
1,官方的镜像是基于debian:jessie或者alpine这些操作系统的,而我们最好用公司目前统一的操作系统ubuntu,便于统一技术栈,统一管理。
2,我们在自己创建pg image的过程中可以自定义客户化的配置、参数等。
3, Dockerfile没有办法mount宿主机器的卷到容器内,所以没有办法将initdb创建数据库时生成的文件放到宿主机器卷上。

 

------创建PG库镜像、搭建主库

1,以下步骤在宿主机器(pg的主库所在机器)操作:

建立PG的bulid image的环境

Dockerfile:

FROM ubuntu:latest
RUN locale-gen en_US.UTF-8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
CMD ["/bin/bash"]

docker build -t ubuntu:utf8 . 

mkdir -p /backup/postgresql 
mkdir -p /storage/docker/postgresql 
docker run -it --name build_pg_img -v /storage/docker/postgresql:/var/lib/postgresql -v /backup/postgresql:/backup -d ubuntu:utf8

如下操作为容器内部的操作:

docker exec -it build_pg_img /bin/bash

apt-get update && apt-get install -y vim wget

vi /etc/apt/sources.list.d/pgdg.list:
增加如下内容:
deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add
apt-get update && apt-get install -y postgresql-9.6

说明:目前默认Ubuntu的源还是pg 9.5,所以要先更新apt的源,然后才能安装pg 9.6。

 

2,查看pg已经安装完毕

root@1c558c35fae8:/# dpkg -l |grep postgre

ii pgdg-keyring 2017.1 all keyring for apt.postgresql.org
ii postgresql-9.6 9.6.2-1.pgdg16.04+1 amd64 object-relational SQL database, version 9.6 server
ii postgresql-client-9.6 9.6.2-1.pgdg16.04+1 amd64 front-end programs for PostgreSQL 9.6
ii postgresql-client-common 180.pgdg16.04+1 all manager for multiple PostgreSQL client versions
ii postgresql-common 180.pgdg16.04+1 all PostgreSQL database-cluster manager
ii postgresql-contrib-9.6 9.6.2-1.pgdg16.04+1 amd64 additional facilities for PostgreSQL
root@1c558c35fae8:/#


3,切换到postgres用户 

root@3fd84ba76393:~# more /etc/passwd |grep post 
postgres:x:105:109:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash

root@3fd84ba76393:~# su - postgres 
postgres@3fd84ba76393:~$ 


4,编辑postgres用户的profile

vi .bash_profile 
#!/bin/bash 
PGHOME=/usr/lib/postgresql/9.6 
export PGHOME 
export PGPORT=5432 
export PGDATA=/var/lib/postgresql/data 
PATH=$PGHOME/bin:$PATH:$HOME/bin 
export PATH 
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PGHOME/lib 
export LD_LIBRARY_PATH 

 

postgres用户加载环境变量:

 . ./.bash_profile


5,初始化PG数据库目录

cd /var/lib/postgresql/ 
mv 9.6 9.6_bak 
mkdir data 
initdb -D /var/lib/postgresql/data -E UTF8 --locale=en_US.utf8
cd /var/lib/postgresql/data 
mkdir pg_log pg_archlog 

mv postgresql.conf  postgresql.conf.old


6,配置postgresql.conf参数 
vi $PGDATA/postgresql.conf : 

postgresql.conf


7,配置pg_hba.conf (按需修改)

vi $PGDATA/pg_hba.conf 
host all all 192.168.0.0/16 md5 
host replication repuser 192.168.0.0/16 md5 


8,启动数据库

pg_ctl start -D /var/lib/postgresql/data 


9,创建扩展

create extension pg_stat_statements; 


10,停止数据库,退出容器

pg_ctl stop -D /var/lib/postgresql/data -m fast 
exit 
exit


11,以下在宿主机器操作: 

从上述初始化完毕的container来创建基础镜像:

docker ps -a |grep build_pg_img 

docker stop build_pg_img

docker commit build_pg_img pg9.6_template 

 

12,创建最终PG镜像的Dockerfile:

vi Dockerfile :
FROM pg9.6_template 
USER postgres 
ENV PGHOME /usr/lib/postgresql/9.6 
ENV PGPORT 5432 
ENV PGDATA /var/lib/postgresql/data 
ENV PATH $PGHOME/bin:$PATH 
ENV LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH 
EXPOSE 5432 
WORKDIR /var/lib/postgresql/data 
CMD ["/usr/lib/postgresql/9.6/bin/postgres", "-D", "/var/lib/postgresql/data"] 


13,基于该dockfile创建新镜像

docker build -t eg_postgresql:9.6 . 


14,启动pg容器:

docker run --name pg_pri -v /storage/docker/postgresql:/var/lib/postgresql -v /backup/postgresql:/backup -p 5436:5432 -d eg_postgresql:9.6 

docker ps |grep pg_pri 
6ccecb527eaa eg_postgresql "/usr/lib/postgresql/" 9 seconds ago Up 9 seconds 5432/tcp pg_pri 


15,以postgres用户进入容器

docker exec -it pg_pri /bin/bash 
然后使用psql即可连接到pg库内部 

postgres@6ccecb527eaa:/$ ps -ef|grep post 
postgres 1 0 0 07:42 ? 00:00:00 /usr/lib/postgresql/9.5/bin/postgres -D /var/lib/postgresql/data 
postgres 6 1 0 07:42 ? 00:00:00 postgres: logger process 
postgres 8 1 0 07:42 ? 00:00:00 postgres: checkpointer process 
postgres 9 1 0 07:42 ? 00:00:00 postgres: writer process 
postgres 10 1 0 07:42 ? 00:00:00 postgres: wal writer process 
postgres 11 1 0 07:42 ? 00:00:00 postgres: autovacuum launcher process 
postgres 12 1 0 07:42 ? 00:00:00 postgres: archiver process 
postgres 13 1 0 07:42 ? 00:00:00 postgres: stats collector process 
postgres 14 0 0 07:43 ? 00:00:00 /bin/bash 
postgres 22 14 0 07:43 ? 00:00:00 ps -ef 
postgres 23 14 0 07:43 ? 00:00:00 /bin/bash 
postgres@6ccecb527eaa:/$ 


16,以root用户进入容器的方式如下:

docker exec -u root -it pg_pri /bin/bash 

 

17,将镜像打包 

docker stop pg_pri

docker save -o eg_postgresql.tar eg_postgresql:9.6 


18,传输到pg从库所在的机器上

scp eg_postgresql.tar core@192.168.17.62:/tmp/.


19,在pg从库机器上load image

docker load -i /tmp/eg_postgresql.tar

 

 

 

------搭建流复制从库

1,使用psql登录pg主库操作

主库创建流复制用户:

CREATE USER repuser replication LOGIN CONNECTION LIMIT 3 ENCRYPTED PASSWORD 'repuser'; 

主库开启备份:

select pg_start_backup('Replition work');

 

2,在主库宿主机操作

cd /storage/docker/postgresql
tar cvf data.tar data
scp data.tar core@192.168.17.62:/tmp/. 

 

3,使用psql登录pg主库操作 

主库结束备份:

select pg_stop_backup(), current_timestamp;

 

4,在pg从库宿主机器上操作

mkdir -p /backup/postgresql
mkdir -p /storage/docker/postgresql
cp /tmp/data.tar /storage/docker/postgresql/.
tar xvf /storage/docker/postgresql/data.tar


5,在pg从库宿主机器上操作

cd /storage/docker/postgresql/data
删除slave端(从master端拷过来的)的pid文件(若有的话) rm -f $PGDATA/postmaster.pid

 

6,编辑recover配置文件

cd /storage/docker/postgresql/data
vi recovery.conf
standby_mode = 'on'
primary_conninfo = 'host=192.168.17.61 port=5436 user=repuser password=repuser keepalives_idle=60'
trigger_file = '/var/lib/postgresql/data/primary_down'


7,修改权限

对应容器内postgres用户的uid、gid是105、109

cd /storage/docker

chown -R 105:109 postgresql

 

8,启动从库容器

docker run --name pg_slv -v /storage/docker/postgresql:/var/lib/postgresql -v /backup/postgresql:/backup -p 5436:5432 -d eg_postgresql:9.6

 

9,进入从库容器

work2 data # docker ps |grep pg_slv
c46867d3d0f5 eg_postgresql:9.6 "/usr/lib/postgresql/" About a minute ago Up About a minute 0.0.0.0:5436->5432/tcp pg_slv
work2 data #

docker exec -it pg_slv /bin/bash

postgres@c46867d3d0f5:~/data$ ps -ef|grep pos 
postgres 1 0 0 03:54 ? 00:00:00 /usr/lib/postgresql/9.6/bin/postgres -D /var/lib/postgresql/data
postgres 6 1 0 03:54 ? 00:00:00 postgres: logger process 
postgres 7 1 0 03:54 ? 00:00:00 postgres: startup process recovering 000000010000000000000003
postgres 8 1 0 03:54 ? 00:00:00 postgres: checkpointer process 
postgres 9 1 0 03:54 ? 00:00:00 postgres: writer process 
postgres 10 1 0 03:54 ? 00:00:00 postgres: wal receiver process streaming 0/3000220
postgres 11 1 0 03:54 ? 00:00:00 postgres: stats collector process 
postgres 12 0 0 03:54 ? 00:00:00 /bin/bash
postgres 19 12 0 03:54 ? 00:00:00 ps -fe
postgres 20 12 0 03:54 ? 00:00:00 grep pos
postgres@c46867d3d0f5:~/data$


postgres@830b2ea66753:/$ psql
psql (9.5.6)
Type "help" for help.

postgres=#

 

现在可以在主库建表测试是否正常同步到从库了。

 

 

------手动主从库切换:


1,停止主库(模拟主库故障)

pg_ctl stop pg_pri

 

2,在从库容器内(pg_slv)执行touch trigger file,触发从库提升为新主库

touch /var/lib/postgresql/data/primary_down

2017-03-29 07:01:40 GMT::@:[7]: LOG: trigger file found: /var/lib/postgresql/primary_down
2017-03-29 07:01:40 GMT::@:[7]: LOG: redo done at 0/100003B0
2017-03-29 07:01:40 GMT::@:[7]: LOG: last completed transaction was at log time 2017-03-29 14:59:51.23113+08
2017-03-29 07:01:40 GMT::@:[7]: LOG: selected new timeline ID: 3
2017-03-29 07:01:40 GMT::@:[7]: LOG: archive recovery complete
2017-03-29 07:01:40 GMT::@:[7]: LOG: MultiXact member wraparound protections are now enabled
2017-03-29 07:01:40 GMT::@:[8]: LOG: checkpoint starting: force
2017-03-29 07:01:40 GMT::@:[1]: LOG: database system is ready to accept connections
2017-03-29 07:01:40 GMT::@:[50]: LOG: autovacuum launcher started
2017-03-29 07:01:40 GMT::@:[8]: LOG: checkpoint complete: wrote 1 buffers (0.0%)

 

此时也会发现原从库的recovery.conf文件的名字变成了recovery.done。

 

3,在新主库进行一些操作,让其与原主库的数据不一致

postgres=# drop table t1;
DROP TABLE
postgres=# create table t2 (id int ,name varchar(20));
CREATE TABLE
postgres=# insert into t2 select generate_series(1,10),repeat('rocky',3);
INSERT 0 10
postgres=# select * from t2;
id | name 
----+-----------------
1 | rockyrockyrocky
2 | rockyrockyrocky
3 | rockyrockyrocky
4 | rockyrockyrocky
5 | rockyrockyrocky
6 | rockyrockyrocky
7 | rockyrockyrocky
8 | rockyrockyrocky
9 | rockyrockyrocky
10 | rockyrockyrocky
(10 rows)

postgres=# \q
postgres@bc97768d38f0:~$

 


4,配置原主库的recovery.conf (要增加选项recovery_target_timeline = 'latest')

standby_mode = 'on'
primary_conninfo = 'host=192.168.17.62 port=5436 user=repuser password=repuser keepalives_idle=60'
trigger_file = '/var/lib/postgresql/data/primary_down'
recovery_target_timeline = 'latest'

 

5,启动原主库为新主库的从库

docker start pg_pri


这个时候会发现日志报错:
2017-03-29 07:05:10 GMT::@:[7]: LOG: entering standby mode
2017-03-29 07:05:10 GMT::@:[7]: FATAL: requested timeline 2 is not a child of this server's history
2017-03-29 07:05:10 GMT::@:[7]: DETAIL: Latest checkpoint is at 0/100003B0 on timeline 1, but in the history of the requested timeline, the server forked off from that timeline at 0/E0ED460.
2017-03-29 07:05:10 GMT::@:[1]: LOG: startup process (PID 7) exited with exit code 1
2017-03-29 07:05:10 GMT::@:[1]: LOG: aborting startup due to startup process failure
2017-03-29 07:05:47 GMT::@:[7]: LOG: database system was shut down at 2017-03-29 07:00:35 GMT

 

6,要将新主库的pg_xlog路径下的最新的.history文件(newst timeline file)copy到主库的pg_xlog路径下

postgres@e9397096d23b:~/data/pg_xlog$ vi 00000003.history 
1 0/10000420 no recovery target specified

 

7,再次启动原主库为从库

docker start pg_pri
日志正常:
2017-03-29 07:10:09 GMT::@:[7]: LOG: entering standby mode
2017-03-29 07:10:09 GMT::@:[7]: LOG: consistent recovery state reached at 0/10000420
2017-03-29 07:10:09 GMT::@:[7]: LOG: invalid record length at 0/10000420
2017-03-29 07:10:09 GMT::@:[1]: LOG: database system is ready to accept read only connections
2017-03-29 07:10:09 GMT::@:[11]: LOG: started streaming WAL from primary at 0/10000000 on timeline 3
2017-03-29 07:10:09 GMT::@:[7]: LOG: redo starts at 0/10000420

 

8,登录到新从库里面,发现数据已经重新同步

postgres@e9397096d23b:/$ psql 
psql (9.5.6)
Type "help" for help.
postgres=# \d
List of relations
Schema | Name | Type | Owner 
--------+--------------------+-------+----------
public | pg_stat_statements | view | postgres
public | t2 | table | postgres
public | testtb | table | postgres
(3 rows)

postgres=# select * from t2;
id | name 
----+-----------------
1 | rockyrockyrocky
2 | rockyrockyrocky
3 | rockyrockyrocky
4 | rockyrockyrocky
5 | rockyrockyrocky
6 | rockyrockyrocky
7 | rockyrockyrocky
8 | rockyrockyrocky
9 | rockyrockyrocky
10 | rockyrockyrocky
(10 rows)

postgres=# \q
postgres@e9397096d23b:

转载于:https://my.oschina.net/rocky0202/blog/861583

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐