四、docker容器互联
基于volume的互联
基于link的互联
基于网络的互联
1、volume:
(1)基础知识
docker文件系统是分层,最上一层是可写层(rootfs),文件修改是拷贝底层文件到上层然后修改,并覆盖底层文件
/var/lib/docker目录下,可以直接用--data-root=/data/docker参数修改到其他地方!
几种文件系统,也就是存储驱动:
Aufs driver是Docker最早支持的driver,但是aufs只是Linux内核的一个补丁集
Device mapper是Linux 2.6内核中提供的一种从逻辑设备到物理设备的映射框架机制,是LVM2的核心,支持块级别的copy on write特性目前,除少数版本如Ubuntu, Docker基本运行在Devicemapper基础上
VFS虚拟文件系统的最大缺陷是不支持copy on write特性,每层都是一个单独的目录,如果新增一个child层,则需要将父级层镜像文件一并复制到新目录
btrfs 非常快,采用btrfs的文件系统级的快照能力来实现layer分层功能,缺点是仍然在进化中,还不够成熟,特别是大量写操作的压力下
overlay 允许用户将一个文件系统与另一个文件系统重叠(overlay),在上层文件系统中记录更改,而下层的文件系统保持不变,比aufs更简单,性能更好,centos7后默认用的就是overlay!
容器里面的写操作:
device mapper是块级别的复制
aufs是将file复制到顶层
高频文件写操作时对于device mapper是非常不高效的(也就是直接高频操作/var/lib/docker/devicemapper/devicemapper/data效率不高),此时采用volume方式:
volume是宿主机上的一个文件夹,映射到容器上,直接对文件夹操作
产生大量日志的系统
数据库类的
daemon.json中配置存储驱动方式:
"storage-driver": "",
启动docker时的volume也可以指定驱动类型
启动容器优化时有很多存储的参数可以配置
https://docs.docker.com/engine/reference/commandline/dockerd//
(2)volume简单用法:
docker run --name=test --rm=true -it -v /jmf java /bin/bash #其实就是使用-v参数
[root@docker-01 docker]# docker run --name=test --rm=true -it -v /jmf ubuntu /bin/bash
root@ffbac3371802:/# ls
bin boot dev etc home jmf lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
进入容器后会发现/jmf目录,那容器里面的这个目录,也就是操作系统层面的volume是放在什么地方呢?
docker inspect test
查看结果中的mounts部分
"Mounts": [
{
"Type": "volume",
"Name": "8d355d65c65b1471e8d7c12ab17a5d9324914f4d5b08f6f4a656914669548ba3",
"Source": "/var/lib/docker/volumes/8d355d65c65b1471e8d7c12ab17a5d9324914f4d5b08f6f4a656914669548ba3/_data",
"Destination": "/jmf",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
(3)指定本地的目录,挂在容器指定目录下:
# docker run --name=test --rm=true -it -v /data/test:/jmf centos /bin/bash
[root@4cb60a953247 /]# ls
anaconda-post.log bin dev etc home jmf lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
# docker inspect test
"Mounts": [
{
"Type": "bind",
"Source": "/data/test",
"Destination": "/jmf",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
#注意:删除容器,本地目录还存在;前面的由于目录是容器内的,所以容器删除也就删除了
可以多个容器中的volume指向同一个本机目录,实现基于文件的共享访问
(4)基于volume的互联,也可以解决跨主机的共享问题:
可以将远程的文件系统挂载到本地,然后docker可以使用volume方式
iscsi
nfs
ceph
分布式文件系统
(5)基于数据容器的单主机互联
docker run --name=test -it -v /jmf ubuntu /bin/bash #提供数据
docker run -rm=true --privileged=true --volumes-from=test -it ubuntu /bin/bash #使用数据
因为在build时候是不能挂载本地目录的,所以建议使用这种方式!!!
2、基于link的互联:
docker run --rm=true --name=mysqlserver -e MYSQL_ROOT_PASSWORD=123456 mysql/mysql-server
[root@docker-01 ~]# docker run --rm=true --name=mysqlserver -e MYSQL_ROOT_PASSWORD=123456 mysql/mysql-server
Initializing database
Database initialized
MySQL init process in progress...
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
/entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
[root@docker-01 docker]# docker exec -it mysqlserver /bin/bash
[root@76282e852a30 /]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.15 MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)
MySQL init process done. Ready for start up.
[root@76282e852a30 /]# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 76282e852a30
docker run --rm=true -it mysql/mysql-server curl 172.17.0.2:3306
docker默认是允许container互通,通过-icc=false关闭互通。一旦关闭了互通,只能通过-link name:alias命令连接指定container.
link方式:--link redis:db的别名,会在/etc/hosts中生成对应的ip映射
eg:--link=myjaveserver:serverM1(目标容器(需要连接的容器),给一个主机名用来代替ip地址进行访问dns名称))
如果强制关掉容器间的互通,也就是--icc=false
/usr/bin/dockerd --icc=false --iptables=true
这时候使用--link时,将只放开端口
docker run --rm=true --link=mysqlserver:myserver -it mysql/mysql-server /bin/bash
iptables会产生很多规则
-A DOCKER -s 172.17.0.4/32 -d 172.17.0.1/32 -i docker0 -o docker0 -p tcp -m tcp --dport 33-6 -j ACCEPT
-A DOCKER -s 172.17.0.1/32 -d 172.17.0.4/32 -i docker0 -o docker0 -p tcp -m tcp --sport 33-6 -j ACCEPT
此时ping时是不通的,但是curl 172.17.0.1:3306能收到包
iptables -t nat -n -L #查看nat表的规则
注意:
link只支持同一物理主机上的容器间的互联,无法解决跨主机间的容期间的互联
跨主机link:代理--升级-->connectable
kubernet会使用代理
各个物理主机各自启用一个ambassador container,ambassador container之间互联。实际生产中基本不用
3、基于网络的互联
(1)端口映射
docker run --rm=true --name=mysqlserver -p 8066:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql/mysql-server
[root@docker-01 docker]# ps -ef |grep docker
root 1451 1 0 08:49 ? 00:00:10 /usr/bin/dockerd -H=unix:///var/run/docker.sock -H=tcp://10.0.18.8:2375
root 1454 1451 0 08:49 ? 00:00:01 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
root 7636 6799 0 11:28 pts/2 00:00:00 docker run --rm=true --name=mysqlserver -p 8066:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql/mysql-server
root 7683 1451 0 11:28 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8066 -container-ip 172.17.0.2 -container-port 3306
root 7687 1454 0 11:28 ? 00:00:00 docker-containerd-shim 84b079b7829b836e5994f006513ff278978be85ba1377c39464f85a3818bd57f /var/run/docker/libcontainerd/84b079b7829b836e5994f006513ff278978be85ba1377c39464f85a3818bd57f docker-runc
发现多了一个进程:/usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8066 -container-ip 172.17.0.2 -container-port 3306
[root@docker-01 docker]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1098/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1181/master
tcp 0 0 10.0.18.8:2375 0.0.0.0:* LISTEN 1451/dockerd
tcp6 0 0 :::22 :::* LISTEN 1098/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1181/master
tcp6 0 0 :::8066 :::* LISTEN 7683/docker-proxy
此时iptables-save,会发现如下信息
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 3306 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8066 -j DNAT --to-destination 172.17.0.2:3306
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 3306 -j ACCEPT
Apparently there are some edge cases without a better workaround (for now):
•localhost<->localhost routing
•docker instance calling into itself via its published port
•and possibly more
注意:每个端口映射将会占掉11M内存资源,有参数去掉这个proxy
(2)直接使用宿主机网络:
[root@server data]# docker run --rm=true --net=host --name network-test -itd centos
61da8186803dbccf1fd8848c791953bf5606e4dddb8bc17287fd205cbfec34cd
[root@server data]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
61da8186803d centos "/bin/bash" 4 seconds ago Up 2 seconds network-test
426ed490001f 10.40.2.230:5000/nginx:1.8.6 "nginx" About an hour ago Up About an hour 80/tcp web
8ee945464e0d registry:latest "/entrypoint.sh /etc…" 26 hours ago Up 25 hours 0.0.0.0:5000->5000/tcp registry
物理机网络:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether 00:50:56:b6:75:6e brd ff:ff:ff:ff:ff:ff
inet 10.40.2.230/24 brd 10.40.2.255 scope global ens160
valid_lft forever preferred_lft forever
inet6 fe80::b53e:a010:62c4:5933/64 scope link
valid_lft forever preferred_lft forever
inet6 fe80::d1a7:ae8d:7ca2:376/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:df:80:85:df brd ff:ff:ff:ff:ff:ff
inet 192.168.3.1/24 brd 192.168.3.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:dfff:fe80:85df/64 scope link
valid_lft forever preferred_lft forever
33: veth7590eca@if32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 7e:94:57:67:4e:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::7c94:57ff:fe67:4edd/64 scope link
valid_lft forever preferred_lft forever
99: vethfc7fee7@if98: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether fa:65:41:de:cb:f0 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::f865:41ff:fede:cbf0/64 scope link
valid_lft forever preferred_lft forever
进入docker容器:
[root@server /]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.3.1 netmask 255.255.255.0 broadcast 192.168.3.255
inet6 fe80::42:dfff:fe80:85df prefixlen 64 scopeid 0x20<link>
ether 02:42:df:80:85:df txqueuelen 0 (Ethernet)
RX packets 175829 bytes 326069469 (310.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 262668 bytes 907467760 (865.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.40.2.230 netmask 255.255.255.0 broadcast 10.40.2.255
inet6 fe80::b53e:a010:62c4:5933 prefixlen 64 scopeid 0x20<link>
inet6 fe80::d1a7:ae8d:7ca2:376 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:b6:75:6e txqueuelen 1000 (Ethernet)
RX packets 23501784 bytes 3581275046 (3.3 GiB)
RX errors 0 dropped 186 overruns 0 frame 0
TX packets 18092808 bytes 997357291 (951.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 3933 bytes 242189 (236.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3933 bytes 242189 (236.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth7590eca: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::7c94:57ff:fe67:4edd prefixlen 64 scopeid 0x20<link>
ether 7e:94:57:67:4e:dd txqueuelen 0 (Ethernet)
RX packets 48353 bytes 319616010 (304.8 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 62549 bytes 618716865 (590.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vethfc7fee7: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::f865:41ff:fede:cbf0 prefixlen 64 scopeid 0x20<link>
ether fa:65:41:de:cb:f0 txqueuelen 0 (Ethernet)
RX packets 301 bytes 22308 (21.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 302 bytes 335320 (327.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
缺点:
同一个镜像,不能启用多个docker实例,极易发生端口冲突
(3)容器公用一个ip网络
docker run --rm=true --name=mysqlserver -e MYSQL_ROOT_PASSWORD=123456 mysql
docker run --rm=true --net=container:mysqlserver mysql/mysql-server ip addr
同一个ip怎么相互访问
使用localhost进行访问:
docker run --rm=true --net=container:mysqlserver mysql/mysql-server curl localhost:3306
(4)使用网桥实现跨主机容器间的访问
a、默认网桥:
默认是使用docker0虚拟网桥,物理主机和容器不是在同一个网段内。没有特殊的要求,比如同一台物理机上容器进行子网隔离等,一般用默认的就好。
配置daemon.json
{
"bip": "192.168.1.5/24",
"fixed-cidr": "192.168.1.5/25",
"fixed-cidr-v6": "2001:db8::/64",
"mtu": 1500,
"default-gateway": "10.20.1.1",
"default-gateway-v6": "2001:db8:abcd::89",
"dns": ["10.20.1.2","10.20.1.3"]
}
注意:
1、"bridge": "","bip": "",这两个不能同时配置
2、"bip"中配置的不能是一个网络192.168.1.0/24,它指网桥的ip,也就是bip的四位最后一位不能是0,否则一直报错如下:
Error starting daemon: Error initializing network controller: Error creating default "bridge" network: failed to allocate gateway (192.168.0.0): Address already in use
3、"default-gateway"不能和"bip"相同,但是又必须属于bip的网络,所以一般不指定,否则很容易报错如下:
Error initializing network controller: Error creating default "bridge" network: auxilairy address: (DefaultGatewayIPv4:10.40.2.1) must belong to the master pool: 192.168.1.0/24
4、测试过的一个网络配置:
# cat /etc/docker/daemon.json
{
"debug": true,
"insecure-registries": ["10.40.2.229:5000"],
"mtu": 1500,
"bip": "192.168.1.1/24",
"fixed-cidr": "192.168.1.0/24"
}
同时开启转发:
$ sysctl net.ipv4.conf.all.forwarding=1
$ sudo iptables -P FORWARD ACCEPT
b、老版本用户自定义网桥——手动实现:
安装虚拟网桥的管理工具bridge-utils(centos和ubuntu中软件名称是一样的)
准备:net.ipv4.ip_forward的值改为1(不是必须),setenforce=0(写死在配置文件中)
chkconfig --levle 2345 NetworkManager off
service NetworkManager stop
rm -rf /etc/udev/rules.d/70-persistent-net.rules #最好删除
配置:
这里我们假设复制的网卡名为br0。首先需要知道的是,如果让br0桥接eth0,那么eth0将不再能获得IP,反而是br0获得了原先eth0的IP。
yum install bridge-utils
cd /etc/sysconfig/network-scripts/
cp ifcfg-eth0 ifcfg-br0
ifcfg-eth0的配置:
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
BRIDGE=br0 #注意添加此项,且没有BOOTPROTO项
ifcfg-br0的配置:
DEVICE=br0
ONBOOT=yes
BOOTPROTO=static
IPADDR=10.152.11.149 #原先eth0的IP
NETMASK=255.255.0.0 #原先eth0的子网掩码
GATEWAY=10.152.255.254 #网关
后重启网络服务,可以发现eth0不再有IP,而br0获得了原先eth0的IP。
# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.000c29c31830 no eth0
# echo "ifup br0" >> /etc/rc.d/rc.local
重启以后,桥接将会失效,原因不明。我曾试过在eth0配置文件中,把BOOTPROTO设置成static或者none,结果都是一样,目前暂时只能通过加入rc.local来解决。
容器启动选项中要定义的选项:
-b指定使用自定义的网桥
-b=br0
--fixed-cidr限制ip地址分配范围
10.211.55.65~10.211.55.126(10.211.55.64/26)
10.211.55.129~10.211.55.190(10.211.55.128/26)
这样容器和宿主机在同一个网段。但是比较麻烦,特别是网段的划分十分不方便,生产实践上很少用
注意:网络上有很多的使用命令操作,是作为临时的方案,ubuntu和centos配置还是有一点区别的
c、用户自定义网桥:——新版
参考:
https://docs.docker.com/network/bridge/
https://docs.docker.com/engine/reference/commandline/network_create/
d、网桥的方案
用户自定义网桥 + 端口映射 (每个端口映射都会耗点内存,应用程序的端口必须进行规划,防止冲突,单台物理机上不允许运行多个同样的镜像;不用担心容器重启之后ip会变化的影响)
大型环境一般不会用这种方案
五、网络
[root@client01 harbor]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
docker network create -d bridge --subnet "192.168.5.1/24" --ip-range "192.168.5.0/24" --gateway "192.168.5.1" -o "com.docker.network.bridge.name"="docker1" docker1
创建一个名字为docker1的网桥网络,系统层面用ip addr可以看到docker1的设备,指定类型、网络等
1、linux路由机制打通网络
docker01
eno16777736: 10.0.18.8/8
docker0: 172.17.0.1/16
docker02
eno16777736: 10.0.18.18/8
docker0: 172.18.0.1/16
docker02上修改Docker0的网络地址,与docker01不冲突
vi /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --bip=172.18.0.1/16 -H=tcp://10.0.18.18:2375 -H=unix:///var/run/docker.sock
systemctl daemon-reload #最好能重启一下机器。
在docker01上执行:route add -net 172.18.0.0/16 gw 10.0.18.18
在docker02上执行:route add -net 172.17.0.0/16 gw 10.0.18.8
[root@docker-01 ~]# route add -net 172.18.0.0/16 gw 10.0.18.18
[root@docker-01 ~]# ip route
default via 10.0.0.2 dev eno16777736 proto static metric 100
10.0.0.0/8 dev eno16777736 proto kernel scope link src 10.0.18.8 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.18.0.0/16 via 10.0.18.18 dev eno16777736
[root@docker-02 ~]# route add -net 172.17.0.0/16 gw 10.0.18.8
[root@docker-02 ~]# ip route
default via 10.0.0.2 dev eno16777736 proto static metric 100
10.0.0.0/8 dev eno16777736 proto kernel scope link src 10.0.18.18 metric 100
172.17.0.0/16 via 10.0.18.8 dev eno16777736
172.18.0.0/16 dev docker0 proto kernel scope link src 172.18.0.1
此时在docker01上ping 172.18.0.1是通的,在docker02上ping 172.17.0.1是通的,如果不通,看看iptables的规则
iptables -F;iptables -t nat -F
容器间互相ping应该也是通的。
docker01上运行:
docker run --rm=true --name=mysqlserver -e MYSQL_ROOT_PASSWORD=123456 mysql/mysql-server
[root@docker-01 ~]# docker exec -it mysqlserver /bin/bash
[root@ce369566d04a /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever
[root@ce369566d04a /]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=62 time=0.566 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=62 time=0.762 m
docker02上运行:
docker run --rm=true name=test centos /bin/bash
[root@5745e39b92de /]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=62 time=0.963 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=62 time=0.693 ms
container重启之后ip是会变化的,有没有什么好的解决方案???
最开始研究k8s的时候,用软件路由器quagga可以实现;现在被fanal改进成host-gw模式,在k8s中不用理会ip会变的状况
2、早期docker网络方案
可以忽略,16年之前的学习openstack时涉猎的内容
(1)基础理论
双网卡独立大二层交换.jpg
overlay 网络.jpg
每个数据包都要进行封装,耗内存,耗网卡
基于ovs(open vswitch)的overlay网络.jpg
neutron网络.jpg
(2)docker网络:
Socketplane被docker公司收购,成为其官方网络的起源
开发者不想操作是否是 VLANs, VXLANs, Tunnels 或者是 TEPs. 对于架构人们最关心的是性能和可靠性。而SocketPlane 在 socket 层面提供了一个网络的抽象层,通过可管理的方式去解决各种网络问题。
主要特性:
Open vSwitch 集成
用于 Docker 的零配置多主机网络
Docker/SocketPlane 集群的优雅增长
支持多网络
分布式 IP 地址管理 (IPAM)
不用去手动敲open vswitch的许多命令
libnetwork:还只是一个构想
libnetwork.jpg
1.将libnetwork集成到Docker Engine
2.在Docker CLI中使用新的network命令
3.撰写『 -net』 参数的文档,以告知用户如何使用它来为容器指定网络
4.在network和endpoint中支持添加『 label』
5.研发新的『 bridge』 插件,以替换Docker目前的实现
6.研发『 分布式bridge』 插件,以支持跨容器网络
目前看到有一些计划是打算将OVS项目关联到Docker上来,从Linux Kernel 3.3开始, OVS项目就是内核的一部分。当我听到这个的时候我觉得是不是脑袋让驴踢了。首先声明我并不是反对使用OVS,实际上,它是一个非常不错的网络工具套件。它的设置比较复杂,对于新手来说有一个陡峭的学习曲线,但是一旦学会, OVS就可以帮你事半功倍。关于这个话题我听到的一个讨论是:“如果OVS工作在Docker上,那么工作一切都变得很美好”。让我告诉你,亲们:如果让我花费大量时间学习它,最后的结果只能是:“还好,可以用”。我并不想说的那么愤世嫉俗,实际情况是在某些常用环境下OVS会崩溃。因此,使用OVS只是一种疯狂的想法罢了。
http://containertutorials.com/network/ovs_docker.html
https://github.com/openvswitch/ovs/blob/master/utilities/ovs-docker
(3)ovs+docker
openvswitch是一个高质量的、多层虚拟交换机,使用开源Apache2.0许可协议,有Nicira Networks开发,主要实现代码为可移植的C代码,目的是让大规模网络自动化可以通过编程扩展,同时仍然支持标准的管理接口和协议(如:netflow,sflow,span,cli,lacp,802.1ag)
openvswitch原理.jpg
GRE:通用路由协议封装
隧道计数(Tunneling)是一种通过使用互联网络的基础设施在网络之间传递数据的方式,使用隧道传递的数据(或负载)可以是不同协议的数据帧或包。隧道协议将其他协议的数据帧或包重新封装然后通过隧道发送。新的帧头提供路由信息,以便通过互联网传递被封装的负载数据
yum install bridge-utils openvswitch(此软件如果没有去找一下或者用源码安装)
建立ovs网桥
添加gre连接
配置docker容器虚拟网桥
为虚拟网桥添加ovs接口
添加不同docker容器网段路由
ovs-vsctl show
ovs-vsctl add-br obr0
ovs-vsctl add-port obr0 gre0
ovs-vsctl set interface gre0 type=gre options:remote_ip=192.168.59.104
ovs-vsctl show
brctl addbr br0
ifconfig br0 192.168.1.1 netmask 255.255.255.0
brctl addif bro obr0
brctl show
配置docker
使用br0代替docker的docker0
systemctl restart docker.service
添加不同docker容器网段路由
现实使用时可以用shell脚本来进行操作
或者使用现有的工具进行、甚至使用自动化的工具、接口调用等
扩展:直接使用docker启动就创建的docker0,修改docker0的ip段即可
openstack的openvswitch.jpg
ovs和docker-01.jpg
ovs和docker-02.jpg
vi /etc/selinux/config
SELINUX=disabled
重启
yum install openvswitch-2.4.0-1.x86_64.rpm #epel库里都没有
# service openvswitch restart
Restarting openvswitch (via systemctl): [ OK ]
# service openvswitch status
ovsdb-server is running with pid 2429
ovs-vswitchd is running with pid 2439
# tailf /var/log/message #查看日志
ovs-vsctl add-br br0
ovs-vsctl add-port br0 gre1 -- set interface gre1 type=gre
option:remote_ip=192.168.18.128
#gre是点对点的,如果有多个,需要将多个添加进去
#添加br0到本地docker0, 使得容器流量通过OVS流经tunnel
brctl addif docker0 br0
docker0的地址的改变
ip link set dev br0 up
ip link set dev docker0 up
iptables -t nat -F;iptables -F
ip route add 172.17.0.0/16 dev docker0
注意:gre、vxlan、fannel原理都差不多,openstack一般用vxlan;而docker集群kubernetes一般用fannel
3、namespace详解:
docker = AUFS + LXC(LXC = cgroup + namespace + chroot…)
linux namespace详解
ovs+docker实战
namespace在内核基础之上(所有命名空间共享底层内核),命名空间之间是隔离的,每个命名空间相当于一个独立的系统,系统内可以跑各种程序。
namespace不止并行关系,其实还存在层级关系(很少用到)
container其实就是将相关进程、资源、账号等等放进一个namespace中,不同容器就是不同的命名空间,相互之间是隔离的
namespace之间点对点.jpg
命名空间ns1的网络接口tap1,是通过软件实现的;
两个命名空间的接口是因为命名空间的隔离而隔离的,彼此无法"看到"对方
veth pair是用于不同network namespace间进行通信的方式, veth pair将一个networknamespace数据发往另一个networknamespace的veth。
namespace交换.jpg
将不同网络命名空间的网络打通----通过linux bridge(2层交换,但是有一个ip地址,可以进行路由转发)
(Linux Bridge可以实现类似交换机的工作模式,将多个不同Namespace上的网卡连通)
docker或者命名空间由于命名空间之间是隔离的,一次某物理主机上的docker1--dockern的eth0都是无法知晓eth0是连接的哪个虚拟接口
[root@docker-01 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242efdb1a96 no
没有运行container,所以,interface是空的。
docker run --rm=true --name=mysqlserver -e MYSQL_ROOT_PASSWORD=123456 mysql/mysql-server
docker run --rm=true --name=mycentos -it centos /bin/bash
[root@docker-01 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno16777736: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:99:94:ba brd ff:ff:ff:ff:ff:ff
inet 10.0.18.8/8 brd 10.255.255.255 scope global eno16777736
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ef:db:1a:96 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:efff:fedb:1a96/64 scope link
valid_lft forever preferred_lft forever
7: veth082c044@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 16:8c:6e:b8:a5:b9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::148c:6eff:feb8:a5b9/64 scope link
valid_lft forever preferred_lft forever
9: veth34485f7@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 52:41:db:e3:87:35 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::5041:dbff:fee3:8735/64 scope link
valid_lft forever preferred_lft forever
[root@docker-01 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242efdb1a96 no veth082c044
veth34485f7
用命令查出mysqlserver地址是172.17.0.2,mycentos地址是172.17.0.3
就无法知道这两个ip连的是veth082c044,还是veth34485f7
docker中的namespace和pid是一样的,container的进程编号就是namespace名称
容器的真正的pid
docker inspect -f '{{.State.Pid}}' containerId 得到容器的真正pid
[root@docker-01 ~]# docker inspect -f '{{.State.Pid}}' mycentos
3393
mkdir -p /var/run/netns
ln -s /proc/3393/ns/net /var/run/netns/3393
#docker的命名空间是建立在/var/run/netns下面,而ip netns工具是按标准的/proc/PID/ns/net找命名空间,所以要做一个连接
ip netns ls
ip netns exec 3393 ip addr #查看3393nanespace中的ip信息
[root@docker-01 ~]# ip netns exec 3393 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:3/64 scope link
valid_lft forever preferred_lft forever
ip netns exec 3393 ethtool -S eth0
9: veth34485f7@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 52:41:db:e3:87:35 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::5041:dbff:fee3:8735/64 scope link
valid_lft forever preferred_lft forever
[root@docker-01 ~]# ip netns exec 3393 ethtool -S eth0
NIC statistics:
peer_ifindex: 9
六、docker管理工具
cAdvisor
compose
swarm
1、cAdvisor
cAdvisor----谷歌开发实时监控工具(被嵌入Kubernetes)
cAdvisor的监控图默认1秒刷新一次,显示最近一分钟的实时数据,不显示汇聚的和历史数据,也没有阀值告警功能,此外它也无法同时监控多个Docker主机,不过由于其简单方便,并且具备很好的实时性能监控能力,所以适合特殊情况下的性能监控和问题排查。
google的cAdvisor,免费开源,实施简单,每个Docker主机上启动一个容器即可通过Web端口监控,
docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest
上述部分参数可能与主机操作系统有关,需要修改;
可参照官方文档:https://github.com/google/cadvisor由于shipyard是在本机8080端口运行。
2、docker compose
与容器技术同样受到关注的微服务架构也在潜移默化的改变着应用的部署方式,其提倡将应用分割成一系列细小的服务,每个服务专注于单一业务功能,服务之间采用轻量级通信机制相互沟通
Docker Compose将所管理的容器分为三层,工程(project),服务(service)以及容器(contaienr)。一个工程当中可包含多个服务,每个服务中定义了容器运行的镜像,参数,依赖。一个服务当中可包括多个容器实例, Docker Compose并没有解决负载均衡的问题,因此需要借助其他工具实现服务发现及负载均衡。Docker Compose v1中定义构建的镜像只存在在一台Docker Swarm主机上, 无法做到多主机共享;后期v2、v3支持swarm的网络。不过一般用来在一台主机跑多个测试服务实例。
docker compose是定义和运行多个docker容器的工具:一个文件–docker-compose.yml,一条命令–docker-compose up会解析容器间的依赖关系先后顺序启动容器
pip install的方式或者用二进制方式安装
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
docker-compose.yml解析
镜像
image:ubuntu:latest
build:/path/to/build/dir默认是本地
dockerfile:使用指定的dockerfile
command:覆盖默认指令
容器配置
links:
- db: database
external_links: #指定不是由compose指定的容器,就是外部容器
- project_redis_1
ports:
- "3000" #随机指定一个端口映射到容器的3000端口
- "8000:80" #将8000映射到容器的80端口
expose:
- "3000" #本容器监听在3000端口上,以环境变量方式导入到和它相关联的容器中
volumes: #定义卷的映射
- /var/lib/mysql:/var/lib/mysql
environment: #定义环境变量
- MYSQL_USER=mysql
官方例子:
参考:https://docs.docker.com/compose/gettingstarted/
docke compose命令集
管理镜像--build/pull
管理服务--up/start/stop/kill/rm/scale(scale使用是不能在yml文件中定定义ports的,防止多个容器端口冲突)
服务状态--ps/logs/port
一次性命令--run
docker-compose up #启动
工程(project)/服务(service)/容器(container)
调用docker-py库与远程docker daemon/swarm api server通讯
按依赖性排序/调度
3、swarm
小型环境中,可以考虑swarm+etcd的集群方案,不过强烈不建议。
##4、其他
很早之前的HECD架构:https://blog.liuts.com/post/242/
docker图形管理界面----tutum(收费软件)
七、Harbor
1、安装相关
是vmware公司开元的一个企业级registry解决方案
官方文档:https://goharbor.io/
下载地址:https://github.com/goharbor/harbor/releases
升级手册:https://github.com/goharbor/harbor/blob/master/docs/migration_guide.md
一般可以选择offline安装方式,最新稳定版本是1.6.2:
wget https://storage.googleapis.com/harbor-releases/release-1.6.0/harbor-offline-installer-v1.6.2.tgz
修改harbor.cfg 相关配置略
执行install.sh
2、1.6.2版本碰到的问题:
(1)仓库管理中的新建目标
目标名: 这个名字可以随便取
目标URL: 目标私有仓库的url,一定不要有项目名;比如http://10.40.2.228,就好啦,不要用http://10.40.2.228/soa
用户名: 目标私有仓库的用户名
密码: 登录密码
验证远程证书: 私有仓库一般不用
(2)镜像复制配置报错
2018-11-27T03:55:17Z [ERROR] [job_logger.go:81]: failed to get project soa from source registry: Get http://10.40.2.230/api/projects?name=soa: dial tcp 10.40.2.230:80: getsockopt: no route to host
a、怀疑compose不能使用默认网络(其实是多此一举的)
参考:https://blog.csdn.net/Kiloveyousmile/article/details/79830810
创建外部网络,并compose使用外部网络
docker network create -d bridge --subnet "192.168.5.1/24" --ip-range "192.168.5.0/24" \
--gateway "192.168.5.1" -o "com.docker.network.bridge.name"="docker1" docker1
version: '2'
services:
log:
image: goharbor/harbor-log:v1.6.2
container_name: harbor-log
restart: always
volumes:
- /var/log/harbor/:/var/log/docker/:z
- ./common/config/log/:/etc/logrotate.d/:z
ports:
- 127.0.0.1:1514:10514
networks:
- docker1
registry:
image: goharbor/registry-photon:v2.6.2-v1.6.2
container_name: registry
restart: always
volumes:
- /data/registry:/storage:z
- ./common/config/registry/:/etc/registry/:z
- ./common/config/custom-ca-bundle.crt:/harbor_cust_cert/custom-ca-bundle.crt:z
networks:
- docker1
environment:
- GODEBUG=netdns=cgo
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "registry"
postgresql:
image: goharbor/harbor-db:v1.6.2
container_name: harbor-db
restart: always
volumes:
- /data/database:/var/lib/postgresql/data:z
networks:
- docker1
env_file:
- ./common/config/db/env
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "postgresql"
adminserver:
image: goharbor/harbor-adminserver:v1.6.2
container_name: harbor-adminserver
env_file:
- ./common/config/adminserver/env
restart: always
volumes:
- /data/config/:/etc/adminserver/config/:z
- /data/secretkey:/etc/adminserver/key:z
- /data/:/data/:z
networks:
- docker1
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "adminserver"
ui:
image: goharbor/harbor-ui:v1.6.2
container_name: harbor-ui
env_file:
- ./common/config/ui/env
restart: always
volumes:
- ./common/config/ui/app.conf:/etc/ui/app.conf:z
- ./common/config/ui/private_key.pem:/etc/ui/private_key.pem:z
- ./common/config/ui/certificates/:/etc/ui/certificates/:z
- /data/secretkey:/etc/ui/key:z
- /data/ca_download/:/etc/ui/ca/:z
- /data/psc/:/etc/ui/token/:z
networks:
- docker1
depends_on:
- log
- adminserver
- registry
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "ui"
jobservice:
image: goharbor/harbor-jobservice:v1.6.2
container_name: harbor-jobservice
env_file:
- ./common/config/jobservice/env
restart: always
volumes:
- /data/job_logs:/var/log/jobs:z
- ./common/config/jobservice/config.yml:/etc/jobservice/config.yml:z
networks:
- docker1
depends_on:
- redis
- ui
- adminserver
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "jobservice"
redis:
image: goharbor/redis-photon:v1.6.2
container_name: redis
restart: always
volumes:
- /data/redis:/var/lib/redis
networks:
- docker1
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "redis"
proxy:
image: goharbor/nginx-photon:v1.6.2
container_name: nginx
restart: always
volumes:
- ./common/config/nginx:/etc/nginx:z
networks:
- docker1
ports:
- 80:80
- 443:443
- 4443:4443
depends_on:
- postgresql
- registry
- ui
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy"
networks:
docker1:
external: true
结果:没能解决问题
将自己带入坑的操作
进入harbor报错容器:
docker exec -it harbor-jobservice /bin/bash
没有发现ping、ip、ifconfig、route等等命令,连yum都没有
curl http://10.40.2.228 # no route to host
curl http://www.baidu.com # 有结果
好像所有的harbor容器都无法curl宿主机!!!
启动其他镜像,然后使用刚手动创建的网络
[root@client01 log]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2e8dcdb7d2b7 bridge bridge local
64302e660195 docker1 bridge local
037c613277df host host local
655d4dd6a34e none null local
[root@client01 harbor]# docker run -it --name test --network docker1 --ip 192.168.5.100 jenkins:latest /bin/bash
jenkins@1b7ef5a96a50:/$ ping -c 2 www.baidu.com
PING www.a.shifen.com (14.215.177.38) 56(84) bytes of data.
64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=1 ttl=51 time=6.57 ms
64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=2 ttl=51 time=6.28 ms
--- www.a.shifen.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 6.289/6.433/6.578/0.165 ms
jenkins@1b7ef5a96a50:/$ ping -c 2 10.40.2.228
PING 10.40.2.228 (10.40.2.228) 56(84) bytes of data.
64 bytes from 10.40.2.228: icmp_seq=1 ttl=64 time=0.117 ms
64 bytes from 10.40.2.228: icmp_seq=2 ttl=64 time=0.109 ms
--- 10.40.2.228 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.109/0.113/0.117/0.004 ms
b、将版本降低:故障依旧
c、和以前同事,讨论,他么有碰到过,不过说应该是网络问题
- 最后细想,容器里面用curl能获取baidu.com,而获取不到宿主机的80端口,可能是iptables的问题
- 将两台harbor的80端口放开-A INPUT -p tcp --dport 80 -j ACCEPT,重新启动harbor(docker-compose down -v;docker-compose up -d)
d、总结:
- 生产部署:
- 上面的docker-compose.yml中一定要将volume的挂载点弄在一个单独的目录下,别全部放在/data目录下,可以考虑/data/harbor/{database,redis…},而harbor线下安装目录(也就是docker-compose操作目录)放到/uar/local/services/harbor目录
- 生产可以考虑做https,参考https://github.com/goharbor/harbor/blob/master/docs/configure_https.md
- 高可用的方式,官方文档没有提供,不过harbor目录下好像有相关的yml文件,暂时还没有玩过,不过可以考虑使用双向复制(域名解析轮询)的方案。可参考:https://www.cnblogs.com/jicki/articles/5801510.html
- kubernetes中使用harbor作为prod的仓库使用:
- docker和iptables的问题:直接修改iptables的配置文件,重启iptables,可能不生效,要重启docker,这点有点坑,可以考虑用centos7的firewalld服务代替iptables如果严格按照,iptables-save、修改文件、重启iptables不知道才能避免
- 当网络命令缺失时,不可以使用docker cp命令将宿主机的命令拷贝到容器中,进行网络故障排查
docker cp /usr/sbin/ip harbor-adminserver:/usr/sbin/ip
docker cp /usr/sbin/route harbor-adminserver:/usr/sbin/route
docker exec -it harbor-adminserver /bin/bash
root [ /harbor ]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
271: eth0@if272: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.5/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
root [ /harbor ]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
当然有一些命令依赖太多,比如yum,要依赖python环境,有点麻烦
八、使用jenkins制作docker镜像
参考:https://jenkins.io/doc/book/installing/
1、安装jenkins
下载带有blueocean的镜像
docker pull jenkinsci/blueocean:1.8.4
docker run \
-u root \
-d \
-p 80:8080 \
-p 50000:50000 \
--name jenkins \
--restart "always" \
-v /data/jenkins:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
jenkinsci/blueocean:1.8.4
说明:
-u root,以某个用户启动jenkins
--rm,容器关闭之后会自动删除
-d,以服务的方式启动
-p 80:8080,映射端口,以供web访问
-p 50000:50000,映射jenkins集群通信端口
-v /data/jenkins:/var/jenkins_home,挂在数据目录到宿主机的/data/jenkins
-v /var/run/docker.sock:/var/run/docker.sock,pipeline语法与agent通信需要
注意:
如果要安装maven等等之类的工具,使用docker exec -it jenkins /bin/bash进去操作
个人建议这种公共组件,使用宿主机部署更好,尤其是centos,可以定制很多启动参数。
如果jenkins的主机还兼着salt-ssh的角色,更加不建议用docker去部署
2、使用jenkins插件
安装CloudBees Docker Build and Publish plugin插件
(1)设计dockerfile
FROM centos
MAINTAINER jiangmingfei "jiangmingfei@globalegrow.com"
RUN mkdir -p /usr/local/services/ #如果目标path不存在,一定要提前创建,否则报错
ADD jdk1.8.0_91 /usr/local/services/jdk1.8.0_91 #注意,目标位置一定要有jdk1.8.0_91
#RUN yum -y install vim
#系统的环境变量
ENV JAVA_HOME "/usr/local/services/jdk1.8.0_91"
ENV CLASS_PATH "$JAVA_HOME/lib:$JAVA_HOME/jre/lib"
ENV PATH "$JAVA_HOME/bin:$PATH"
(2)设置jenkins
步骤:
- 系统设置–>配置–>Docker Builder–>Docker URL–>tcp://10.40.2.230:2376–>测试连通性
注意:
- 10.40.2.230的防火墙要对容器放开
a、准备参数
Genaral-->参数化构建过程-->
名称:program_tag
默认值:latest
描述:给镜像打上版本的标签
b、将需要添加到images里面的文件拷贝到jenkins当前workspace
构建-->执行shell
#!/bin/bash
source /etc/profile
cp -r /usr/local/services/jdk1.8.0_91 ./
c、添加build任务:
构建-->
Docker Build and Publish-->
Repository Name: soa/jdk # 项目名/Repository名
Tag: $program_tag #镜像的tag,这里可以直接使用前面的参数
Docker Host URI:tcp://10.40.2.230:2376 # 可以是本机的docker的tcp连接端口
Docker registry URL: http://10.40.2.229:80 #一定要有端口号,否则默认还是用443
Registry credentials:**** #配置了,不过好像没有生效
高级里面的参数:
No Cache
Force Pull
Skip Decorate #去掉镜像制作中job的装饰,在job name中不加其他的东西,否则jenkins很难看
Skip tag as latest #这个不勾的话,每次都给新的镜像生成一个latest的tag
Dockerfile Path:/data/dockerfiles/jdk/Dockerfile #jenkins主机专门弄一个目录出来存放Dockerfile
d、删除镜像制作主机上的本地镜像
构建-->Execute Docker command
Docker command: Remove image
Image Name: 10.40.2.229:80/soa/jdk:$program_tag #只删除本次制作的