Docker—镜像和容器
- 好记性不如烂笔头
关于Docker Image
-
docker image类似于层状结构,其底层基于Linux Kernel构造。
-
每一个镜像包括着Linux内核和基础的 Centos/Ubuntu 镜像,在其上层可构建自定义镜像
-
我们可以把每一个镜像看作成一台拥有了我们定制内容的 Linux 服务器
镜像获取及镜像加速器设置
- 我们可以从docker镜像仓库源中去拉取镜像到我们本地机器进行使用
- 镜像仓库源 类似 maven 仓库的概念
- 通过 docker search 命令可以查找docker仓库中的镜像
- 我们可以自己设置我们自己的镜像仓库源
vi /etc/docker/daemon.json
{
"registry-mirrors": ["http://hub-mirror.c.163.com"]
}
or
{
"registry-mirrors": ["https//orptaaqe.mirror.aliyuncs.com"]
}
# 重启docker服务 or 重启docker
systemctl restart docker.service
# 国内仓库镜像加速地址
# Docker中国区官方镜像
https://registry.docker-cn.com
# 网易镜像源
http://hub-mirror.c.163.com
# 中国科技大学
https://docker.mirrors.ustc.edu.cn
# 阿里云容器服务
https://cr.console.aliyun.com/
同样也可以通过Dockerfile自己去构建镜像
Dockerfile镜像制作
- docker提供Dockerfile文件用来构建镜像
Dockerfile语法
# FROM 指定基础镜像
# 例如指定ubuntu:14.04作为基础镜像
FROM ubuntu:14.04
# RUN 在镜像内部执行一些命令,例如:安装软件、配置环境、安装相关命令等等
RUN groupadd -r mysql && useradd -r -g mysql mysql
# ENV 设置变量的值,如下。可以通过 docker run --e key=value进行修改,可以使用 ${MYSQL_MAJOR} 来取值
ENV MYSQL_MAJOR 5.7
# LABEL 设置镜像标签
LABEL email="hh@163.com" version="1.0"
LABEL name="zh2020yy"
# VOLUME 指定数据的挂载目录,改变外部文件夹的内容,会影响到容器内文件夹
VOLUME /var/lib/mysql
# COPY 将主机的文件复制到镜像内,如果目录不存在,会自动创建所需要的目录,注意只是复制,不会提取和解压
COPY demo.sh /usr/local/bin/
# ADD 将主机的文件复制到镜像内,和COPY类似,ADD命令会对压缩文件进行提取和解压
ADD demo.zip /etc/zh/
# WORKDIR 指定镜像的工作目录,之后的命令都是基于此目录工作,若不存在则创建
# 这几个命令的意思是创建 /usr/local/tomcat 文件夹,接下来的命令在该目录下执行
WORKDIR /usr/local
WORKDIR tomcat
RUN touch test.txt
# CMD 容器启动的时候会执行的命令,若有多个CMD命令,则最后一个生效
CMD mysqld
# ENTRYPOINT 和CMD的使用类似
# 和CMD命令不同的是,docker run执行时,会覆盖CMD的命令,而ENTRYPOINT不会被覆盖
ENTRYPOINT ["demo.sh"]
# EXPOSE 指定镜像要暴露的端口,启动镜像时,可以使用 -p 将该端口映射给宿主机
EXPOSE 3306
自己制作一个镜像
-
首先自己准备一个Java jar包,上传到服务器的指定位置
-
创建Dockerfile文件
-
编写Dockerfile文件
- MAINTAINER:设置镜像所有者
FROM openjdk:8
MAINTAINER zh2020
LABEL name="dockerfile-demo" version="1.0" author="zh2020"
COPY spring_boot_docker-0.0.1-SNAPSHOT.jar dockerfileEx.jar
# 启动容器后执行的命令
CMD ["java", "-jar", "dockerfileEx.jar"]
- 基于Dockerfile构建镜像
docker build -t my-docker-image .
-
构建成功,得到新的镜像
-
基于镜像创建container
docker run -d --name zh -p 6666:8080 imageID
- 通过 localhost:6666 进行访问,验证
镜像相关操作
# 删除所有镜像
docker rmi -f $(docker image ls)
# 通过 容器创建镜像,假设我们有一个容器名字叫做 containerA
docker commit containerA newImageName
镜像推送
- 镜像仓库源中有许多镜像,我们也可以把自己创建的镜像推送到镜像仓库中去
- 这里以docker官方仓库为例 https://hub.docker.com/ (也可以是阿里云or自己搭建的云服务器)
- 首先进行注册、登录。拥有自己的账户
- 登录docker官方仓库,并创建自己的仓库。仓库创建完成之后会拥有属于自己的仓库名称,假如仓库名称是 myrepo 账户名称是 account
- 那么镜像推送的步骤为
# 首先进行登录
docker login --username=https://hub.docker.com/
# 输入用户名和密码 ,假设推送的镜像id为 a1b2c3
# 通过docker tag 给镜像打上标签 这里 v1 表示镜像的标签
docker tag a1b2c3 account/myrepo:v1
# 然后进行push
docker push account/myrepo:v1
Docker harbor
- 同理,类似于maven私服。docker提供搭建docker harbor的方式,可作为私服使用。
# 首先从 github 上下载 harbor项目,选择合适的版本
https://github.com/goharbor/harbor/releases
# 在一台安装了 docker-compose 的机器,上传并解压
tar -zxvf xxx.tar.gz
# 解压完成之后,进入到 harbor 目录,修改 harbor.cfg 文件,主要修改 IP 地址为当前机器的 IP 地址,同时可以修改 harbor 密码
# 安装 harbor
sh install.sh
# 最后浏览器访问 IP,输入用户名和密码即可
关于Docker container
- 通过 docker run 的方式运行 image,来创建容器
container资源限制
- 运行中的container会占用物理资源
- 可以通过 docker stats 来查看资源情况
- 同样可以使用 docker 自由的内存资源限制命令,如下
内存限制
# --memory 限制容器使用内存大小为 100M
docker run -d --memory 100M --name containerName imageID
CPU限制
# --cpu--shares 权重,如下,这里配置权重为10
docker run -d --cpu--shares 10 --name containerName imageID
图形化资源监控
- 通过weaveworks scope可以更直观地对 docker 容器资源进行监控
- https://github.com/weaveworks/scope
sudo curl -L git.io/scope -o /usr/local/bin/scope
sudo chmod a+x /usr/local/bin/scope
scope launch ip
# 停止 scope
scope stop
container常见操作
# 删除所有的 container
docker rm -f $(docker ps -a)
# 进入一个容器当中
docker exec -it containerID bash
# 查看 container 日志
docker logs containerID
# 查看容器详情信息
docker inspect containerID
# 停止启动容器
docker stop/start containerID
网卡与Docker
相关预备知识
- 网络相关认识——Configure networking
- 计算机网络七层模型
- 高级层、传输层、基础层
- 计算机之间数据通信,数据包通过装包、拆包
- 每一个计算机中拥有网卡,通过网卡建立通信
- docker中的网络,网卡信息
- 通过ipconfig可查看网卡信息
- 网卡的定义
- 计算机网络中,计算机中要能够进行通信的硬件支撑
- 每一个网卡会有特定唯一的Mac地址
- 通过命令行查看机器网卡的方式
# 以文件的形式去查看机器的网卡
ls /sys/class/net
# 查看机器网卡
ip a
ip link show
ip a解读
- link/ether:MAC地址
- inet:绑定的IP地址
网卡即配置文件
- 在Linux中网卡对应的就是文件,通过一下方式可以查找到对应的网卡文件
cat /etc/sysconfig/network-scripts/ifcfg-eth0
- 可以通过修改 ifcfg 文件的形式给网卡 添加/删除 IP地址
ip addr add 192.168.0.100/24 dev eth0
ip addr delete 192.168.0.100/24 dev eth0
网卡的启动与关闭
- 重启网卡
service network restart
systemctl restart network
- 启动或关闭某个网卡
ifup/ifdown eth0 or ip link set eth0 up/down
Network Namespace
- 在Linux中,网络的隔离是通过 network namespace 来管理的。不同的 network namespace 互相隔离
查看当前机器上的network namespace
# 查看
ip netns list
# 添加
ip netns add nsl
# 删除
ip netns delete nsl
创建一个namespace
# 1.创建一个network namespace nsl
ip netns add nsl
# 2.查看该 namespace 下的网卡情况
ip netns exec nsl ip a
# 3.启动nsl上的网卡
ip netns exec nsl ifup lo
or
ip netns exec nsl ip link set lo up
# 4.再次查看进行验证 发现state 变成了 UNKOWN
ip netns exec nsl ip a
# 5.再次创建一个network namespace
ip netns add ns2
# 6.现在想让两个namespace网络联通起来,两个namespace在本地拥有各自的网卡。网卡是网络通信的基石
#为了两个 ns 彼此能够通信,为每个 ns 分别配置网卡和IP
# 通过 veth pair: Virtual Ethernet Pair 技术创建网卡
# 创建出来的网卡能够彼此联通,网卡创建完成之后,分别派给 ns
# 7.创建一对 link ,也就是接下来通过 veth pair 技术连接的link
ip link add veth-ns1 type veth peer name veth-ns2
# 8.查看 link 的情况
ip link
# 9. 将 veth-ns1 加入 ns1中, veth-ns2加入ns2中
ip link set veth-ns1 netns ns1
ip link set veth-ns2 netns ns2
# 10.查看 宿主机 和 ns1、ns2的link情况
ip link
ip netns exec ns1 ip link
ip netns exec ns2 ip link
# 11.此时 veth-ns1和veth-ns2还没有IP地址,通信仍然缺少必要条件
ip netns exec ns1 ip addr add 192.168.0.11/24 dev veth-ns1
ip netns exec ns2 ip addr add 192.168.0.12/24 dev veth-ns2
# 12.再次查看,发现 state 是 DOWN ,仍然没有IP地址
ip netns exec ns1 ip link
ip netns exec ns2 ip link
# 13.启动 veth-ns1 和 veth-ns2
ip netns exec ns1 ip link set veth-ns1 up
ip netns exec ns2 ip link set veth-ns2 up
# 14.再次查看,发现 state 是 UP ,同时有 IP
ip netns exec ns1 ip a
ip netns exec ns2 ip a
# 15.此时两个 network namespace 互相 ping 一下,发现可以进行 ping 通
ip netns exec ns1 ping 192.169.0.12
ip netns exec ns2 ping 192.168.0.11
Docker和网卡
- 每一个container对应一个 network namespace 并且是独立的
- 当我们创建多个容器之后,容器之间是能够互相 ping 通的。这里是如何进行 ping 通的呢?
container网络-Bridge
# 查看宿主机 网络
ip a
# 查看容器网络
docker exec -it containerName ip a
- 在宿主机中 ping 一下容器的网络,可以发现能够ping通
- 由此可以推测,在container中有一个 eth0 和 centos 的 docker0 中的一个 veth3 是成对的。类似于 之前安装的 veth-ns1和veth-ns2
# 命令确认 brctl
yum install bridge-utils
brctl show
- 通过测试,发现容器与容器之间也能够ping通
- 联通方式如下
- docker0中有着多个 veth ,每一个对应着一个容器的 veth
- 这种网络连接方法称之为 Bridge
- 可以通过命令查看docker中的网络模式
# Bridge也是docker中默认的网络模式
docker network ls
# 检查 Bridge
docker network inspect bridge
在容器中是可以访问互联网的
- 容器通过docker0种配对的 veth 以 NAT的方式进行网络地址的转换
- NAT 通过 iptables 来实现的
创建自定义network
# 1.创建一个 network 类型为 bridge
docker network create demo-bri
or
docker network create --subnet=172.18.0.0/24 demo-bri
# 2.查看已有的 network
docker network ls
# 3.查看 demo-bri 详情信息
docker network inspect demo-bri
# 4. 创建新的容器,并指定使用的 network
docker run -d --name container-name --network demo-bri imageID
# 5. 查看 container-name 的网络信息
docker exec -it container-name ip a
# 6. 查看网卡信息
ip a
# 7. 查看网卡接口
brctl show
# 8. 此时使用不同 network 的容器,无法 ping 通
docker exec -it network1 ping network2-ip
# 9. 使用 connect 进行连接
docker network connect demo-bri network1-container
# 10. 此时查看 demo-bri 网络,能够发现 network1-container 也在其中
# 11. 此时,进入到 network1-container 中,不仅可以通过 ip ping通,而且可以通过名字 ping 通,因为都连接到了自定义的 bridge 上
Container网络-HOST & NONE
Host模式
# 1. 创建一个 容器,名字为 demo-host 并且指定网络为 host
docker run -d --name demo-host --network host imageID
# 2. 此时查看IP地址,可以发现和宿主机是一样的
docker exec -it demo-host ip a
None模式
# 1. 创建一个容器,名字为 demo-none ,并且指定网络为 none
docker run -d --name demo-none --network none imageID
# 2. 查看IP地址 发现没有IP地址
docker exec -it demo-none ip a
Docker数据持久化
数据持久化的关键在于 Volume 设置
# 查看 volume 可查看目前 docker 容器的 卷 列表
docker volume ls
# 查看 volume 卷详情信息
docker volume inspect volumeID
# volume 使用, my_volume代表宿主机目录, /var/lib/mysql代表容器中的目录
docker run *** -v my_volume:/var/lib/mysql ***
- 值得注意的是,当容器被删除后,创建出的 volume 并不会被删除,而且还可以再次使用
MySQL集群搭建
使用docker搭建mysql数据库集群
# first of all
# 拉取 pxc 镜像,pxc 镜像是 docker 用来搭建mysql集群的一个成熟的解决方案
docker pull percona/percona-xtradb-cluster:5.7.21
# 创建一个单独的网段给 mysql 数据库集群来使用
docker network create --subnet=ip/port pxc-net
# 查看详情
docker network inspect pxc-net
# 删除
docker network rm pxc-net
# 删除 volume
docker volume rm v1
# 创建 volume
docker volume create --name volumeName
# 运行三个 PXC 容器,搭建 PXC[mysql] 集群
docker run -d -p 3301:3306 -v v1:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=jack123 \
-e CLUSTER_NAME=PXC \
-e XTRABACKUP_PASSWORD=jack123 \
--privileged --name=node1 \
--net=pxc-net --ip 172.18.0.2 pxc
docker run -d -p 3302:3306 -v v2:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=jack123 \
-e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=jack123 \
-e CLUSTER_JOIN=node1 \
--privileged --name=node2 --net=pxc-net --ip 172.18.0.3 pxc
docker run -d -p 3303:3306 -v v3:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=jack123 \
-e CLUSTER_NAME=PXC \
-e XTRABACKUP_PASSWORD=jack123 \
-e CLUSTER_JOIN=node1 \
--privileged --name=node3 --net=pxc-net --ip 172.18.0.4 pxc
# 工具连接测试
数据库集群负载均衡
通过对外暴露一个地址,来合理使用集群数据库服务
# 首先拉取 haproxy 镜像
docker pull haproxy
# 创建 haproxy ,使用 bind mounting 的方式
touch /tmp/haproxy/haproxy.cfg
haproxy.cfg
global
#工作目录,这边要和创建容器指定的目录对应 chroot /usr/local/etc/haproxy #日志文件
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_monitor
#统计报告格式
stats realm Global\ statistics
#登陆帐户信息
stats auth admin:admin
#数据库负载均衡
listen proxy-mysql
#访问的IP和端口,haproxy开发的端口为3306
#假如有人访问haproxy的3306端口,则将请求转发给下面的数据库实例
bind 0.0.0.0:3306
#网络协议
mode tcp
#负载均衡算法(轮询算法)
#轮询算法:roundrobin
#权重算法:static-rr
#最少连接算法:leastconn
#请求源IP算法:source
balance roundrobin
#日志格式
option tcplog
#在MySQL中创建一个没有权限的haproxy用户,密码为空。
#Haproxy使用这个账户对MySQL数据库心跳检测
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
#使用keepalive检测死链
option tcpka
创建 haproxy 容器
docker run -it -d -p 8888:8888 -p 3306:3306 -v /tmp/haproxy:/usr/local/etc/haproxy \
--name haproxy01 --privileged --net=pxc-net haproxy
启动 haproxy
docker exec -it haproxy01 bash haproxy -f /usr/local/etc/haproxy/haproxy.cfg
在MySQL数据库上创建用户,用于心跳检测
CREATE USER 'haproxy'@'%' IDENTIFIED BY ''; [小技巧[如果创建失败,可以先输入一下命令]:
drop user 'haproxy'@'%';
flush privileges;
CREATE USER 'haproxy'@'%' IDENTIFIED BY '';
]
浏览器访问验证
http://centos_ip:8888/dbs_monitor
# 用户名密码都是:admin
连接 haproxy01
ip:centos_ip
port:3306
user:root
password:123456