docker网络扩展
1 docker run参数
常用选项说明
-d, --detach=false, 指定容器运行于前台还是后台,默认为false
-i, --interactive=false, 打开STDIN,用于控制台交互
-t, --tty=false, 分配tty设备,该可以支持终端登录,默认为false
-u, --user="", 指定容器的用户
-a, --attach=[], 登录容器(必须是以docker run -d启动的容器)
-w, --workdir="", 指定容器的工作目录
-c, --cpu-shares=0, 设置容器CPU权重,在CPU共享场景使用
-e, --env=[], 指定环境变量,容器中可以使用该环境变量
-m, --memory="", 指定容器的内存上限
-P, --publish-all=false, 指定容器暴露的端口
-p, --publish=[], 指定容器暴露的端口
-h, --hostname="", 指定容器的主机名
-v, --volume=[], 给容器挂载存储卷,挂载到容器的某个目录
--volumes-from=[], 给容器挂载其他容器上的卷,挂载到容器的某个目录
--cap-add=[], 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities
--cap-drop=[], 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities
--cidfile="", 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法
--cpuset="", 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
--device=[], 添加主机设备给容器,相当于设备直通
--dns=[], 指定容器的dns服务器
--dns-search=[], 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件
--entrypoint="", 覆盖image的入口点
--env-file=[], 指定环境变量文件,文件格式为每行一个环境变量
--expose=[], 指定容器暴露的端口,即修改镜像的暴露端口
--link=[], 指定容器间的关联,使用其他容器的IP、env等信息
--lxc-conf=[], 指定容器的配置文件,只有在指定--exec-driver=lxc时使用
--name="", 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
--net="bridge", 容器网络设置:
bridge 使用docker daemon指定的网桥
host //容器使用主机的网络
container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源
none 容器使用自己的网络(类似--net=bridge),但是不进行配置
--privileged=false, 指定容器是否为特权容器,特权容器拥有所有的capabilities
--restart="no", 指定容器停止后的重启策略:
no:容器退出时不重启
on-failure:容器故障退出(返回值非零)时重启
always:容器退出时总是重启
--rm=false, 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
--sig-proxy=true, 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理
2 docker 网络
# 创建网络名称空间
ip netns list 查看
ip netns delete test1 删除
ip netns add test1 新增
ip netns add test2 新增
ip netns exec text1 ip a 查看网络名称空间test1的ip
ip link 查看linux网卡的二层信息
ip netns exec text1 ip link 查看名称空间text1网卡的二层信息
ip netns exec test1 ip link set dev lo up (ip link set dev lo up)把lo网卡启动
ip link add veth-test1 type veth peer name veth-test2 添加两个veth,分别是veth-test1和veth-test2
ip link set veth-test1 netns test1 把veth-test1添加到test1的名称空间中
ip netns exec text1 ip link 可以看到已经被添加到test1中了
ip link set veth-test2 netns test2
ip netns exec text2 ip link
ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1 给设备新增ip地址veth-test1
ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2 给设备新增ip地址veth-test2
ip netns exec test1 ip link set dev veth-test1 up 启动veth-test1
ip netns exec test2 ip link set dev veth-test3 up 启动veth-
ip netns exec test1 ip a 可以看到ip地址有了
ip netns exec test1 ping 192.168.1.2 发现能ping 通
bridge网络
docker network ls
docker network inspect 网络id号
ip a 本地有docker0和veth
docker0是docker的
veth是某个容器的,他们两个名称空间相连接
docker exec 容器id ip a
查看容器网卡可以看到有个eth..,它跟veth是一对parr,连到了主机的docker0上
brctl命令
yum install bridge-utils
brctl show 可以看到docker0 有个interface--》 veth,就是通过ip a看到的那个veth
再创建一个容器
docker network inspect 网络id号 containers又多了个veth
ip a 又多个一个veth
bractl show 发现docker0上有两个veth了
容器访问外网通过nat地址转换
# 容器直接link
# 后台访问数据库,两个容器,需要知道ip地址去连接
docker run -di --name=test1 centos:centos7 # 启一个test1容器,没有做端口映射
docker run -di --name=test2 --link test1 centos:centos7 # 再启一个test2容器,加上--link test1
进入到test2中, ping test1 可以ping通(不需要直接知道test1的ip地址)
进入到test1容器中ping test2 无法ping通,这种方式只是单向连接
应用:启一个mysql容器,不做端口映射;再用link方式启一个django项目容器,django可以通过容器名字连通mysql
网络桥接方式,双向连接
# 新建bridge
docker network create -d bridge 名字
docker network ls
brctl show 可以看到多了一个bridge:br-id号,通商贸docker network ls的id号
# 启动容器,指定使用的网络
docker run -d --name test3 --network my-bridge busybox
brctl show 可以看到br-id号有接口了
# 两个网络连接到一起
docker network connect my-bridge test2 两个参数,一个是网络,一个是容器
docker network inspect bridge
docker network inspect my-bridge 发现test2 即连接到了bridge又连接到了my-bridge上
现在test3内直接 ping test2可以ping通:因为如果两个容器连接到了用户创建的网络上,默认就link好了,相互通过名字ping通
# host和none网络
docker run -d --name test3 --network none busybox
docker network inspect none 发现test3在none中
进入到容器
ip a 发现该容器只有一个lo回环地址
孤立的,除了exec进去,其他都不能访问它,只需要本地使用,产生数据的服务器
docker run -d --name test3 --network host busybox
docker network inspect host 发现test3在none中,没有ip地址
进入到容器
ip a 发现该容器跟主机共享一套namespace,没有自己的一套
这样如果宿主机80端口被占用,容器就不能再起在80端口了
跨服务器的多容器通信,最简单的方式,用端口映射,下面是官方提供的方式,已弃用
官方提供的
## 多机通信(不同机器的redis和flask如何通信)
docker用的是VXLAN(一层一层包起来)
# overlay方式通过etcd来实现,多主机通信
# 保证不通机器上的容器ip地址不冲突
# 每台机器上分别启动etcd的进程
# 下载etcd
wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
# 解压etcd
tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
cd etcd-v3.0.12-linux-amd64
nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://192.168.205.10:2380 \
--listen-peer-urls http://192.168.205.10:2380 \
--listen-client-urls http://192.168.205.10:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.205.10:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
--initial-cluster-state new&
# 另一台机器
wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
cd etcd-v3.0.12-linux-amd64/
nohup ./etcd --name docker-node2 --initial-advertise-peer-urls http://192.168.205.11:2380 \
--listen-peer-urls http://192.168.205.11:2380 \
--listen-client-urls http://192.168.205.11:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.205.11:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
--initial-cluster-state new&
# 检查cluster状态
./etcdctl cluster-health
'''
member 21eca106efe4caee is healthy: got healthy result from http://192.168.205.10:2379
member 8614974c83d1cc6d is healthy: got healthy result from http://192.168.205.11:2379
cluster is healthy
'''
# 重启docker
/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.10:2379 --cluster-advertise=192.168.205.10:2375&
# 另一台
sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.11:2379 --cluster-advertise=192.168.205.11:2375&
# 创建overlay网络
docker network create -d overlay demo
docker network ls
docker network inspect demo
# 没有在nod2上做,但是被etcd同步过去了
#通过查看etcd的key-value, 我们获取到,这个demo的network是通过etcd从node1同步到node2的
# 创建容器,连接到demo上,在node2上创建
docker run -d --name test1 --net demo busybox sh -c "while true; do sleep 3600; done"
# 在node2上创建,就会提示test1已经被用过了
docker run -d --name test2 --net demo busybox sh -c "while true; do sleep 3600; done"
# 两个地址不一样
docker network inspect demo 有两台机器上的两个地址
# 两个容器可以ping通
docker exec test1 ping 10.0.0.3
docker exec test1 ping test2 也可以
3 持久化存储和数据共享
# 基于本地的Volume:在容器创建或者run的时候,通过 -v指定
# 基于plugin的Volume:插件方式,第三方方案,如NAS,aws
# ## volume的类型
#1 受管理的data Volume,由docker后台自动创建(Data volume)
#2 绑定挂载的Volume,具体挂载可以由用户指定 (Bind Mouting)
#################Data volume
## 启动一个mysql的容器
docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
docker volume ls 可以看到刚刚创建容器的voluem
docker volume id号 删除
docker inspect id号 可以看到mount到的本地某个位置
# 再创建,也会创建一个volume
# 删除容器,volume是不会被删除的(数据不会丢)
# 两个容器可以共用一个volume
docker run -d -v mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
docker run -d --name=mysql -v mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:5.7
docker run -di --name=mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -v mysql:/var/lib/mysql mysql:5.7
# 进入到容器,创建一个数据库
# 停掉容器,删除容器
sudo docker volume ls 文件还在
# 重新一个容器,使用该volume
docker run -d -v mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
# 进入到容器,看到数据库还在
###############Bind Mouting
# index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>hello</title>
</head>
<body>
<h1>Hello Docker! </h1>
</body>
</html>
# Dockerfile
FROM nginx:latest
WORKDIR /usr/share/nginx/html
COPY index.html index.html
# 构建
docker build -t liuqingzheng/nginx_demo:v1 .
# 启动容器
docker run -d -p 80:80 --name web iuqingzheng/nginx_demo:v1
# 把当前路径映射到容器目录
docker run -d -v $(pwd):/usr/share/nginx/html -p 80:80 --name web iuqingzheng/nginx_demo:v1
# 进入到容器,操作容器目录,宿主机跟着改动
#####实战演练
# Dockerfile
FROM python:2.7
COPY . /skeleton
WORKDIR /skeleton
RUN pip install -r requirements.txt
EXPOSE 5000
ENTRYPOINT ["scripts/dev.sh"]
# 构建
docker build -t liuqingzheng/flask_demo:v1 .
# 启动容器
docker run -d -p 80:5000 --name flask liuqingzheng/flask_demo:v1
# 删除容器
# 重新操作
docker run -d -v $(pwd):/skeleton -p 80:5000 --name flask liuqingzheng/flask_demo:v1
# 这样修改了代码,直接访问,页面也改变了
4 mysql配置文件位置
# 容器内部mysql配置文件位置
mysql --help | grep my.cnf
'''
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf
'''
ls /etc/mysql
# conf.d my.cnf my.cnf.fallback mysql.cnf mysql.conf.d
# my.cnf文件最后一行
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
# 除加载 my.cnf 配置文件外,还会到/etc/mysql/conf.d/目录下加载其他配置文件。
#当然可以配置多个!includedir这样做的好处是可以把不同目的或功能的配置放在不同的多个文件下,然后由 my.cnf 去统一加载这些配置。避免所有配置在一个文件中
## 演示
# 在当前目录下创建文件夹conf.d,内部vim my.cnf
# 加入:设置id号
[mysqld]
server-id=109
# 创建并启动容器
docker run -d -v ./conf.d/:/etc/mysql/conf.d -v mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
# 进入容器
# 进入mysql
#执行:可以看到id为109
show variables like 'server_id';