本方案主要目的是学习, 该方案不太合适于企业项目html
白话点, 是个提供了必要环境
的虚拟机(相似于java的导入部分包同样和c++的头文件差很少), 因此它比普通的VMWare或者VirtualBox安装的虚拟机要轻
java
整体来讲相似于jvm那样的存在, 只不过jvm运行的是java编译的字节码, docker运行的是各类组件, 好比mysql, redis, zookeeper或者咱们的项目node
docker镜像相似于系统安装包ISO
, 或者咱们对某个程序的备份, 将这个备份压缩成rar压缩包
, 备份了不少程序的数据和配置, 咱们只要把这个压缩包丢给别人, 别人解压并使用这个程序mysql
容器相似于咱们的程序(前面的镜像是压缩包), 能够直接运行linux
总结
镜像和容器的关系是 一个镜像对应能够多个容器(只要你建立的多)c++
建立或编辑该文件:redis
vi /etc/docker/daemon.json
在该文件中输入以下内容:算法
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.ccs.tencentyun.com",
"https://registry.docker-cn.com"
]
}
复制代码
service docker start # 开启docker
service docker stop # 关闭docker
service docker restart # 重启docker
复制代码
docker save java > /home/java.tar.gz
docker load < /home/java.tar.gz
复制代码
docker search java
复制代码
docker pull java
复制代码
docker images
复制代码
docker inspect java
复制代码
[
{
"Id": "sha256:d23bdf5b1b1b1afce5f1d0fd33e7ed8afbc084b594b9ccf742a5b27080d8a4a8",
"RepoTags": [
"java:latest"
],
"RepoDigests": [
"java@sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d"
],
"Parent": "",
"Comment": "",
"Created": "2017-01-17T00:52:54.890877145Z",
"Container": "4b4ab1e131616e04a88f26f9811e5847dd0c3ec5f8178b634b388d3c510ee606",
"ContainerConfig": {
"Hostname": "33842653d6db",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"LANG=C.UTF-8",
"JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64",
"JAVA_VERSION=8u111",
"JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1",
"CA_CERTIFICATES_JAVA_VERSION=20140324"
],
"Cmd": [
"/bin/sh",
"-c",
"/var/lib/dpkg/info/ca-certificates-java.postinst configure"
],
"ArgsEscaped": true,
"Image": "sha256:7cfe1ce37b990ea20d6377b8901f5ffccd463ed2f965e9730d834e693b53baec",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": [],
"Labels": {}
},
"DockerVersion": "1.12.3",
"Author": "",
"Config": {
"Hostname": "33842653d6db",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"LANG=C.UTF-8",
"JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64",
"JAVA_VERSION=8u111",
"JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1",
"CA_CERTIFICATES_JAVA_VERSION=20140324"
],
"Cmd": [
"/bin/bash"
],
"ArgsEscaped": true,
"Image": "sha256:7cfe1ce37b990ea20d6377b8901f5ffccd463ed2f965e9730d834e693b53baec",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": [],
"Labels": {}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 643195347,
"VirtualSize": 643195347,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/fcdfe412499e0b1afe9cb8d6800eb56af9c578b1c49fbf0fc9f38fead4f32b2d/diff:/var/lib/docker/overlay2/5d79e6646df2342376ba59d8d21b70142d0e3fd0c9a0de2229c1cfa4c2d98e93/diff:/var/lib/docker/overlay2/47b9afdc585a2c847d112283d7d884f00140dab44c33203eeeccc4a592a23378/diff:/var/lib/docker/overlay2/9565b7df775e50948f7713b8a1b1ba6610eb055c958bbd23a7646b4414ccefab/diff:/var/lib/docker/overlay2/dd8233c055d2241a6e52a0f0acd48220f87a75e50fbe2a7355445bcc75bbfbb9/diff:/var/lib/docker/overlay2/64bb2d108355eb53a495cdb6804e602baa651888a27c10c19dfb0fa2351648b6/diff:/var/lib/docker/overlay2/3fb4d1d79e7b1966b16dfb4d7dcde2ac6ac602f932395acf2c5d3bd0573a9c67/diff",
"MergedDir": "/var/lib/docker/overlay2/09e28e456caf00dd0ab82af1f594f248f05e0e64a4b931f69251ab2f1c9c4df3/merged",
"UpperDir": "/var/lib/docker/overlay2/09e28e456caf00dd0ab82af1f594f248f05e0e64a4b931f69251ab2f1c9c4df3/diff",
"WorkDir": "/var/lib/docker/overlay2/09e28e456caf00dd0ab82af1f594f248f05e0e64a4b931f69251ab2f1c9c4df3/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:a2ae92ffcd29f7ededa0320f4a4fd709a723beae9a4e681696874932db7aee2c",
"sha256:0eb22bfb707db44a8e5ba46a21b2ac59c83dfa946228f04be511aba313bdc090",
"sha256:30339f20ced009fc394410ac3360f387351641ed40d6b2a44b0d39098e2e2c40",
"sha256:ce6c8756685b2bff514e0b28f78eedb671380084555af2b3833e54bb191b262a",
"sha256:a3483ce177ce1278dd26f992b7c0cfe8b8175dd45bc28fee2628ff2cf063604c",
"sha256:6ed1a81ba5b6811a62563b80ea12a405ed442a297574de7440beeafe8512a00a",
"sha256:c3fe59dd955634c3fa1808b8053353f03f4399d9d071be015fdfb98b3e105709",
"sha256:35c20f26d18852b74cc90afc4fb1995f1af45537a857eef042a227bd8d0822a3"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
复制代码
docker rmi java
复制代码
启动镜像会默认建立出一个容器sql
docker run -it --name myjava java bash
使用bash运行保持控制台方式运行docker run -it --name myjava -p 9000:8080 -p 9050:8050 java bash
以控制台方式运行java而且映射了java的端口8080到主机的9000, 映射到java的8050到主机的9050端口docker run -it -name myjava -v /home/project:/soft --privileged java bash
映射java应用的路径/soft
到主机的/home/project
路径并使用--privileged
给了修改权限mkdir /home/project
docker run -it --name myjava -p 9000:8080 -p 9050:8050 -v /home/project:/soft --privileged java bash
复制代码
添加
[option] -d
建立和之后台方式启动容器docker
docker pause myjava # 能够在另外一个控制台暂停
docker unpause myjava # 能够在另外一个控制台执行
docker stop myjava # 能够中止掉容器
docker start -i myjava
复制代码
docker ps -a # 查看全部容器, 包括未运行的容器
docker ps # 查看正在运行的容器
复制代码
docker rm myjava
删除容器
建立docker内部网络比较安全, 内部只要对外部提供端口即可, 通常用于集群内部网络时使用
docker network create net1
docker network inspect net1
docker network rm net1
复制代码
docker network create --subnet=172.18.0.0/24 net1
这得从 docker 容器的文件系统提及。出于效率等一系列缘由,docker 容器的文件系统在宿主机上存在的方式很复杂,这会带来下面几个问题:
为了解决这些问题,docker 引入了数据卷(volume) 机制。数据卷是存在于一个或多个容器中的特定文件或文件夹,这个文件或文件夹以独立于 docker 文件系统的形式存在于宿主机中。数据卷的最大特定是:其生存周期独立于容器的生存周期。
docker volume create --name v1
例如:
root@ubuntu:/# docker volume create --name node1
node1
root@ubuntu:/# docker volume inspect node1
[
{
"CreatedAt": "2020-07-08T14:03:16+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/node1/_data",
"Name": "node1",
"Options": {},
"Scope": "local"
}
]
复制代码
它把卷建立到了宿主机的/var/lib/docker/volumes/node1/_data
目录下
docker pull percona/percona-xtradb-cluster:5.7
图片中笔者原本想配置mysql8.0的pxc方案, 但主机的ssl配置成功后,从机的ssl一直验证不经过(笔者给予了几个文件足够的权限777). 主机ssl的几个文件必须是读写执行权限全给才可以验证成功, 但从机的
custom.cnf
权限若是仍是读写执行权限将会被忽略, 因此笔者建立了两个config文件夹, 里面存了两个custom.cnf
配置文件, 只有权限不一样, 虽然这个配置文件再也不被忽略, 但仍是不行, 会不断的重复尝试链接ssl//:172.18.0.2:4567
, 没辙. 只能回到5.7的怀抱
docker搭建mysql8.0的pxc方案相关资料
docker network create --subnet=172.18.0.0/24 pxc_net1
docker volume create v1
docker volume create v2
docker volume create v3
docker volume create v4
docker volume create v5
docker volume create backup
复制代码
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc -e XTRABACKUP_PASSWORD=123456 -v v1:/var/lib/mysql -v backup:/data --privileged --name pxc_node1 --net=pxc_net1 --ip=172.18.0.2 percona/percona-xtradb-cluster:5.7
复制代码
集群这几个地方要改
docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pxc_node1 -v v2:/var/lib/mysql -v backup:/data --privileged --name pxc_node2 --net=pxc_net1 --ip=172.18.0.3 percona/percona-xtradb-cluster:5.7
docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pxc_node1 -v v2:/var/lib/mysql -v backup:/data --privileged --name pxc_node2 --net=pxc_net1 --ip=172.18.0.3 percona/percona-xtradb-cluster:5.7
docker run -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pxc_node1 -v v3:/var/lib/mysql -v backup:/data --privileged --name pxc_node3 --net=pxc_net1 --ip=172.18.0.4 percona/percona-xtradb-cluster:5.7
docker run -d -p 3309:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pxc_node1 -v v4:/var/lib/mysql -v backup:/data --privileged --name pxc_node4 --net=pxc_net1 --ip=172.18.0.5 percona/percona-xtradb-cluster:5.7
docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pxc_node1 -v v5:/var/lib/mysql -v backup:/data --privileged --name pxc_node5 --net=pxc_net1 --ip=172.18.0.6 percona/percona-xtradb-cluster:5.7
复制代码
docker pull haproxy
mkdir ~/docker/haproxy
cd ~/docker/haproxy
vi haproxy.cfg
复制代码
写入
global
#工做目录
chroot /usr/local/etc/haproxy
#日志文件,使用rsyslog服务中local5日志设备(/var/log/local5),等级info
log 127.0.0.1 local5 info
#守护进程运行
daemon
defaults
log global
mode http
#日志格式
option httplog
#日志中不记录负载均衡的心跳检测记录
option dontlognull
#链接超时(毫秒)
timeout connect 5000
#客户端超时(毫秒)
timeout client 50000
#服务器超时(毫秒)
timeout server 50000
#监控界面
listen admin_stats
#监控界面的访问的IP和端口
bind 0.0.0.0:8888
#访问协议
mode http
#URI相对地址
stats uri /dbs
#统计报告格式
stats realm Global\ statistics
#登录账户信息
stats auth admin:123456
#数据库负载均衡
listen proxy-mysql
#访问的IP和端口
bind 0.0.0.0:3306
#网络协议
mode tcp
#负载均衡算法(轮询算法)
#轮询算法:roundrobin
#权重算法:static-rr
#最少链接算法:leastconn
#请求源IP算法:source
balance roundrobin
#日志格式
option tcplog
#在MySQL中建立一个没有权限的haproxy用户,密码为空。Haproxy使用这个帐户对MySQL数据库心跳检测
# CREATE USER 'haproxy'@'%' IDENTIFIED by ''; FLUSH PRIVILEGES;
option mysql-check user haproxy
server MySQL_1 172.18.0.2:3306 check weight 1 maxconn 2000
server MySQL_2 172.18.0.3:3306 check weight 1 maxconn 2000
server MySQL_3 172.18.0.4:3306 check weight 1 maxconn 2000
server MySQL_4 172.18.0.5:3306 check weight 1 maxconn 2000
server MySQL_5 172.18.0.6:3306 check weight 1 maxconn 2000
#使用keepalive检测死链
option tcpka
复制代码
docker run -it -d -p 4001:8888 -p 4002:3306 -v /root/docker/haproxy:/usr/local/etc/haproxy --name h1 --net=pxc_net1 --ip 172.18.0.8 --privileged haproxy
docker run -it -d -p 4003:8888 -p 4004:3306 -v /root/docker/haproxy:/usr/local/etc/haproxy --name h2 --net pxc_net1 --ip 172.18.0.9 --privileged haproxy
复制代码
记住这句上面注释掉的CREATE USER 'haproxy'@'%' IDENTIFIED by ''; FLUSH PRIVILEGES;
这句话若是不在数据库中建立好用户, 将会在出现Haproxy没法感知mysql是否启动的状况, 由于她须要经过数据库建立的这个帐号haproxy监控数据库状况(因此你能够不给这个帐号任何权限, 只要他们访问就行)
因此docker exec -it pxc_node1 /usr/bin/mysql -uroot -p123456
进入容器, 而后复制CREATE USER 'haproxy'@'%' IDENTIFIED by ''; FLUSH PRIVILEGES;
去建立这个帐户
只要在一个节点建立就好, 其余数据库会同步更新
进入docker中的haproxy控制台中 docker exec -it h1 bash
加载配置文件haproxy -f /usr/local/etc/haproxy/haproxy.cfg
以后访问 http://192.168.0.135:4001/dbs
至此配置haproxy配置完成了, 咱们使用navicat链接下试试
cf014fbc9ef7 haproxy "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:4002->3306/tcp, 0.0.0.0:4001->8888/tcp h1
复制代码
我是尝试链接下 4002
端口
如今咱们尝试下关闭掉数据库节点pxc_node1
docker stop pxc_node1
咱们新建完毕
这里咱们其余库都更新完毕了, 但pxc_node1
是空的
咱们如今从新开启pxc_node1
节点看下, 是否是那个表被添加到这个节点了
发现没法开启这个节点了(这是怎么回事???)
vi /var/lib/docker/volumes/v1/_data/grastate.dat
修改 safe_to_bootstrap: 0
为safe_to_bootstrap: 1
再次尝试启动这个节点
虽然成功了, 可是数据没被同步过去
甚至还会出现这个问题(由于是轮训, 因此随机出现没法找到数据库问题)
如今咱们尝试修改下, 别的数据库中的数据(非pxc_node1
数据库节点)
这数据就这么丢了
如今咱们重启docker, 而后在依次从新启动节点
单个Haproxy节点不具有高可用, 必需要给个备机防止主机没了, 致使咱们的服务没法访问的问题
linux提供了虚拟IP的技术, 咱们的双机热备须要利用它(虚拟ip就是在一个网卡上能够对不一样的程序提供不一样的虚拟ip)
使用keepalived方式以抢占虚拟IP的方式完成, 因此咱们须要在docker haproxy内部配置环境
完整方案
apt-get update
apt-get upgrade
apt install keepalived
复制代码
Keepalived的配置文件是/etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
172.18.0.201
}
}
复制代码
启动keepalived serivce keepalived start
启动它
以上操做都在docker容器中操做
而后咱们测试下主机是否可以ping通docker内部的网络下的虚拟机
ping 172.18.0.201
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
172.18.0.202
}
}
复制代码
serivce keepalived start
启动它
退出回到宿主机, ping 172.18.0.202
看下是否可以ping的通
vi /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.0.155
}
}
virtual_server 192.168.0.155 8888 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
real_server 172.18.0.201 8888 {
weight 1
}
real_server 172.18.0.202 8888 {
weight 1
}
}
virtual_server 192.168.0.155 3306 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
real_server 172.18.0.201 3306 {
weight 1
}
real_server 172.18.0.202 3306 {
weight 1
}
}
复制代码
启动keepalived, systemctl start keepalived
(宿主机是centOS7, 因此使用systemctl
)
再ping下ping 192.168.0.155
[root@centOS ~]# ping 192.168.0.155
PING 192.168.0.155 (192.168.0.155) 56(84) bytes of data.
From 192.168.0.144 icmp_seq=1 Destination Host Unreachable
From 192.168.0.144 icmp_seq=2 Destination Host Unreachable
From 192.168.0.144 icmp_seq=3 Destination Host Unreachable
From 192.168.0.144 icmp_seq=4 Destination Host Unreachable
^C
--- 192.168.0.155 ping statistics ---
4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3000ms
pipe 4
[root@centOS ~]# ping 192.168.0.155
PING 192.168.0.155 (192.168.0.155) 56(84) bytes of data.
64 bytes from 192.168.0.155: icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from 192.168.0.155: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 192.168.0.155: icmp_seq=3 ttl=64 time=0.039 ms
^C
复制代码
注意下: keepalived的启动须要一点点时间, 上面控制台输出
Destination Host Unreachable
是由于压根没启动完毕
咱们回到真正的主机(window上)在ping下, 看下行不行 ping 192.168.0.155
正在 Ping 192.168.0.155 具备 32 字节的数据:
来自 192.168.0.155 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.0.155 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.0.155 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.0.155 的回复: 字节=32 时间<1ms TTL=64
192.168.0.155 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 0ms,最长 = 0ms,平均 = 0ms
复制代码
ok, 配置完成
咱们在navicat
上链接下
ip: 192.168.0.155
用户: root
密码: 123456(我为了简便设置了简单的密码, 实际项目中千万别这么简单)
端口: 3306
复制代码
完成
- 但存在一个问题, 每次启动docker, 都要进入docker h1和h2容器中再启动keepalived, 挺麻烦的, 放心后面会慢慢解决的
- 还存在一个问题, 用户没法知道keepalived哪些节点能用, 哪些节点不能用了 keepalived容易出现脑裂, 因此我也不太推荐使用这种方案, 本方案主要目的是学习
冷备份和热备份之间的关系是会不会实际影响到咱们的业务(锁住备份区域,或者干脆阻塞它), 冷备会, 热备份不会, 显而易见, 选热备
而热备方案中又有全量备份
、增量备份
和物理备份
真的是, 各类名词看腻了, 说白了就是一次备份是否是直接 copy 仍是 copy + 1 这样的不断备份, 还有一种就是忽略了文件系统结构的备份
咱们选择xtrabackup
作热备方案
还记得前面我在建立集群时加的参数么?
-v backup:/data
这个, 如今咱们要将数据库备份映射到这个目录, 若是前面建立集群时, 没有增长这个参数须要stop后删除的从新建立
若是咱们没有添加映射备份目录, 那么须要
docker stop pxc_node1
docker rm pxc_node1
docker run -d -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pxc_node2 --net=pxc_net1 --ip=172.18.0.2 -p 3306:3306 -v v1:/var/lib/mysql -v backup:/data --privileged --name pxc_node1 percona/percona-xtradb-cluster:5.7
复制代码
如今咱们进入docker容器中的pxc_node1
节点 看看这个容器运行的系统是什么版本的linux系统
red hat 或者 centOS 系统因此咱们须要使用yum
去更新
docker exec -it pxc_node1 bash
bash-4.2$ yum update
Loaded plugins: fastestmirror, ovl
ovl: Error while doing RPMdb copy-up:
[Errno 13] Permission denied: '/var/lib/rpm/.dbenv.lock'
You need to be root to perform this command.
复制代码
exit退出, 而后docker exec -it --user root pxc_node1 bash
or docker exec -it --user=root pxc_node1 bash
yum clean all
yum makecache
yum update
yum install wget
wget https://repo.percona.com/yum/percona-release-latest.noarch.rpm
rpm -ivh percona-release-latest.noarch.rpm
rm percona-release-latest.noarch.rpm
yum list | grep percona
复制代码
进行一次全量热备
innobackupex --user=root --password=123456 /data/backup/full
复制代码
回到宿主机, 看看
docker volume inspect backup
复制代码
cd /var/lib/docker/volumes/backup/_data
复制代码
就能够看到已经备份了
全部的pxc_node*
节点都是共享的 backup
目录
还原也同样
docker exec -it pxc_node1 bash # 进入节点
rm -rf /var/lib/mysql/* # 删除掉本来的数据
# 将尚未提交的事务回滚
innobackupex --user=root --password=lezhu123456 --apply-back /data/backup/full/2018-04-15_05-09-07/
# 恢复
innobackupex --user=root --password=lezhu123456 --copy-back /data/backup/full/2018-04-15_05-09-07/
复制代码
不是我说, 有更好的选择千万别选pxc
待续...