一 应用场景描述
现在需要搭建一个内部邮件服务器用于接收zabbix报警信息,邮件服务器选用iRedmail开源邮件系统。但是由于可用服务器不多,邮件服务器的使用压力也不大,于是考虑在一台空闲的物理机上安装KVM虚拟机或者Docker容器的方式来部署iRedmail邮件服务器。考虑到目前Docker容器很流行的,使用KVM虚拟机还要配置和管理KVM虚拟机,不如使用Docker容器来得方便。于是就有了这篇文章。
二 Docker基础知识
目前最新版本的Docker在CentOS6.5上运行不良,最好升级操作系统到CentOS7并升级内核到4.0以上,以下有说明。
在CentOS7上面安装Docker
yum -y install docker*
启动Docker服务
service docker start
获取最近的CentOS镜像
docker pull centos
获取CentOS6的镜像
docker pull centos:6
查看本地所有的镜像
docker p_w_picpaths
查看单个镜像
docker p_w_picpaths centos
docker run -v /usr/sbin:/usr/sbin --rm centos /usr/sbin/ip addr show
--rm 容器停掉后会被删除
docker run -v /usr/sbin:/usr/sbin --name=test centos /usr/sbin/ip addr show
--name 给容器改名字
docker start -i test 开启test容器
docker run --name=mybash -it centos /bin/bash
可以在容器中安装软件
yum -y install net-tools
docker ps -a列出所有的容器
docker ps 列出正在运行的容器
docker start -ai mybash 开启容器
docker run --name="log_test" -v /dev/log:/dev/log --rm centos logger "Testing logging to the host"
journalctl -b | grep Testing
docker inspect mybash 查看容器的元数据信息
docker inspect --format='``.`NetworkSettings`.`IPAddress`' mybash
docker inspect --format='``.`State`.`Pid`' mybash
docker inspect --format='``.`HostConfig`.`PortBindings`' mybash
docker exec 在一个运行中的容器中执行命令
docker exec -it mybash /bin/bash
docker stop mybash
docker kill --signal="SIGHUP" mybash
docker rm goofy_wozniak
docker rm clever_yonath furious_shockley drunk_newton
d
docker run -i centos:6 /bin/bash -c "yum clean all;yum -y update;yum -y install -y httpd;yum clean all"
docker ps -l 查看最近创建过的容器
docker commit -m "centos6 with httpd" -a "john wang" ff0bfd94552a centos_httpd 从容器中创建镜像提交到本地镜像库
docker run -d -p 8080:80 centos_httpd:latest /usr/sbin/httpd -DFOREGROUND
使用centos_httpd这个最新的镜像运行一个容器,映射容器的80端口到本地的8080端口
curl http://localhost:8080
从Dockerfile中创建镜像
mkdir -p httpd-project
cd httpd-project
docker build -t centos_httpd .
docker run -d -t --name=mycentos_httpd -p 80:80 -i centos_httpd:latest /usr/sbin/httpd -DFOREGROUND
从构建的镜像运行容器
# netstat -tulnp|grep 80
tcp6 0 0 :::80 :::* LISTEN 26472/docker-proxy
# curl localhost:80Your Web server test is successful.
docker tag 5c2ed3dea01f centos 给镜像打tag
docker tag 474ff279782b cnegus/myrhel7
docker save -o centos6.tar centos:latest 保存镜像为tar文件
cat centos6.tar|docker import - john/centos6
docker rmi 340d0ced58bb 删除镜像
docker rmi $(docker p_w_picpaths -a -q) 删除所有镜像
三 Docker网络知识
Docker启动后会默认创建一个名为docker0的虚拟网卡,一般是172.17.42.1/16,这个地址是可以变更的,创建一个容器的时候默认使用--net=bridge参数为容器分配一个docker0相同网段的IP。Docker创建一个容器的时候会创建一对对端网卡,一个分配给容器默认为eth0,一个绑定到docker0,名字一般是vethxxxx。详细知识请参考官方文档。
由于docker0默认为容器分配的IP不满足需求,我们配置的iredmail邮件服务器需要有内网网络的固定IP。所以这里要对docker的网络配置做些更改。
本文都是在CentOS7上安装Docker
1.在Docker主机重新创建一个桥接网卡
cd /etc/sysconfig/network-scripts/
cp ifcfg-enp4s0 ifcfg-br0
vim ifcfg-enp4s0
TYPE=Ethernet
BRIDGE=br0
BOOTPROTO=none
#IPADDR=172.28.10.125
#NETMASK=255.255.255.0
#GATEWAY=172.28.10.27
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_FAILURE_FATAL=no
NAME=enp4s0
UUID=5cabea9a-df74-4ac0-a8ae-42fb61357a09
DEVICE=enp4s0
ONBOOT=yes
vim ifcfg-br0
TYPE=Bridge
BOOTPROTO=static
IPADDR=172.28.10.125
NETMASK=255.255.255.0
GATEWAY=172.28.10.27
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_FAILURE_FATAL=no
NAME=br0
#UUID=5cabea9a-df74-4ac0-a8ae-42fb61357a09
DEVICE=br0
ONBOOT=yes
然后重新启动网卡
service network restart
查看网卡信息
# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.28.10.125 netmask 255.255.255.0 broadcast 172.28.10.255
inet6 fe80::1e6f:65ff:fed7:6531 prefixlen 64 scopeid 0x20<link>
ether 1c:6f:65:d7:65:31 txqueuelen 0 (Ethernet)
RX packets 371701 bytes 179614127 (171.2 MiB)
RX errors 0 dropped 24 overruns 0 frame 0
TX packets 104043 bytes 8964068 (8.5 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp4s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 1c:6f:65:d7:65:31 txqueuelen 1000 (Ethernet)
RX packets 279799000 bytes 46612531640 (43.4 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 104058 bytes 8964998 (8.5 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 0 (Local Loopback)
RX packets 12 bytes 1124 (1.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 12 bytes 1124 (1.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
如果Docker已经启动,先关掉docker
service docker stop
vim /etc/sysconfig/docker
添加
OPTIONS='-b=br0 --selinux-enabled'
然后启动docker
service docker start
查看docker进程
ps -ef|grep docker
root 11358 1 0 09:00 ? 00:00:00 /usr/bin/docker -d -b=br0 --selinux-enabled
docker会修改iptables的nat表
# iptables -t nat -L -n
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.28.10.0/24 0.0.0.0/0
创建一个CentOS6的容器用于安装iredmail
#docker run -it --net=none --name=iredmail --hostname=mx.xxx.com --add-host=mx.xxx.com:127.0.0.1 --privileged=true centos:6 /bin/bash
--name 指定容器的名称
--hostname 指定容器的主机名,生成容器后没法在容器内部修改主机名,修改容器的容器的配置文件也无法生效,所以创建容器的时候最好指定主机名
进入iredmail容器
# docker exec -it iredmail /bin/bash
[root@7e34924492f3 /]# ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
由于创建iredmail容器的时候使用的是--net=none,docker将不会为这个容器分配IP地址
根据官方文档的步骤我写了个脚本可以自动为iredmail容器添加固定IP。
docker_container_ip.sh
#!/bin/bash #author: john wang #this script is used to auto add specified private ip for docker container #container can be id or name such as 7e34924492f3 or iredmail container=iredmail bridge=br0 mac=12:34:56:78:9a:bc ip=172.28.10.72/24 gateway=172.28.10.27 docker_status=$(ps -ef|grep docker|grep $bridge|grep -v grep|grep -v $0) if [ "$docker_status" == "" ];then echo -e "\e[035mDocker is not running\e[0m" echo -e "\e[035mStarting docker\e[0m" /sbin/service docker start else echo -e "\e[035mDocker is already running\e[0m" fi container_status=$(docker ps|grep $container) function set_ip () { echo -e "\e[035m set ip $ip gateway $gateway mac $mac for $container\e[0m" #### set_ip $1 #### id=$(docker ps|grep $container|awk '{print $1}') if [ "$id" != "" ];then A=veth${id:0:4} B=eth${id:0:4} ### Error: argument "veth7e34924492f3" is wrong: "name" too long ### use ${id:0:4} to cut container id, only use prefix 4 characters pid=$1 mkdir -p /var/run/netns ln -sf /proc/$pid/ns/net /var/run/netns/$pid > /dev/null ########### #### /opt/script/docker_container_ip.sh: line 43: ip: command not found #### /opt/script/docker_container_ip.sh: line 44: brctl: command not found #### tail -f /var/spool/mail/root #### ########### /usr/sbin/ip link add $A type veth peer name $B > /dev/null 2>&1 /usr/sbin/brctl addif $bridge $A > /dev/null 2>&1 /usr/sbin/ip link set $A up > /dev/null 2>&1 /usr/sbin/ip link set $B netns $pid > /dev/null 2>&1 /usr/sbin/ip netns exec $pid ip link set dev $B name eth0 > /dev/null 2>&1 /usr/sbin/ip netns exec $pid ip link set eth0 address $mac > /dev/null 2>&1 /usr/sbin/ip netns exec $pid ip link set eth0 up > /dev/null 2>&1 /usr/sbin/ip netns exec $pid ip addr add $ip dev eth0 > /dev/null 2>&1 /usr/sbin/ip netns exec $pid ip route add default via $gateway > /dev/null 2>&1 ### 2>&1 else echo -e "\e[035mContainer ID is not valid\e[0m" fi } if [ "$container_status" != "" -a "$docker_status" != "" ];then #create a pair of peer interfaces A and B #bind the A end to the bridge,and bring it up #place B inside the container's network namespace #rename to eht0,and activate it with a free IP pid=$(docker inspect -f '``.`State`.`Pid`' $container) set_ip $pid else echo -e "\e[035m **********WARNING container $container is not running **********\e[0m" echo -e "\e[035m **********Starting container $container\e[0m" docker start $container pid=$(docker inspect -f '``.`State`.`Pid`' $container) set_ip $pid fi
添加定时任务
*/2 * * * * /opt/script/docker_container_ip.sh >> /tmp/docker_container_ip.log
这样就可以避免iredmail容器重启或者docker重新启动后容器内的IP消失
root@mx /]# ifconfig eth0 Link encap:Ethernet HWaddr 12:34:56:78:9A:BC inet addr:172.28.10.72 Bcast:0.0.0.0 Mask:255.255.255.0 inet6 addr: fe80::1034:56ff:fe78:9abc/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:7642 errors:0 dropped:0 overruns:0 frame:0 TX packets:517 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:618391 (603.8 KiB) TX bytes:39509 (38.5 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b) [root@mx /]# hostname
使用CentOS7默认的内核运行Docker时会莫名其妙出现内核报错,导致CentOS重启后无法启动
升级内核到4.2.3解决这个问题
参考文章
http://dl528888.blog.51cto.com/2382721/1655142
四 安装和配置iredmail
然后参考http://john88wang.blog.51cto.com/2165294/1610504
这里的步骤安装和配置iredmail
按照配置完iredmail后需要启动相关服务,安装后iredmail后提示重启启动服务器,但是使用Docker容器重启后并不会自动启动相关服务
执行脚本/opt/script/iredmail_service.sh
#!/bin/bash services="amavisd cbpolicyd clamd clamd.amavisd crond dovecot httpd iredapd mysqld postfix rsyslog saslauthd slapd spamassassin sshd iptables" for i in $(echo $services) do service $i start done
测试可以使用后就可以使用docker commit将这个运行的iredmail容器制作成镜像提交到本地镜像库
docker commit -m "centos with iredmail" -a "john wang" 3fffabaa79cd centos_iredmail
五 从Dockerfile中创建iredmail镜像
可以使用Dockerfile创建iredmail镜像
mkdir -p docker_iredmail
cd docker_iredmail/
vim Dockerfile
FROM centos:6 ### Update and customize centos packages. RUN yum -y install wget vim lrzsz tar bzip2 telnet man ### Download and unzip iRedMail. ENV IREDMAIL iRedMail-0.9.2 RUN wget https://bitbucket.org/zhb/iredmail/downloads/$IREDMAIL.tar.bz2 ;\ tar xvjf $IREDMAIL.tar.bz2 ;\ rm $IREDMAIL.tar.bz2 RUN rpm -ivh http://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm ### Install iRedMail. RUN echo "127.0.0.1 mx.xxx.com" > /etc/hosts #RUN hostname mx.xxx.com COPY depends.txt /$IREDMAIL/ COPY config /$IREDMAIL/ RUN for i in $(cat /$IREDMAIL/depends.txt);\ do \ yum -y install $i;\ done RUN chmod +x /$IREDMAIL/iRedMail.sh RUN echo y | /$IREDMAIL/iRedMail.sh
vim depends.txt
这个文件是安装和配置iredmail需要的软件包
MySQL-python acl altermime amavisd-new awstats clamav-db clamd cluebringer crontabs dos2unix dovecot dovecot-managesieve dovecot-pigeonhole fail2ban httpd logwatch mod_ssl mod_wsgi mysql-server openldap-clients openldap-servers patch perl-LDAP perl-Mail-SPF php php-common php-gd php-imap php-intl php-ldap php-mbstring php-mcrypt php-mysql php-pear-Net-IDNA2 php-pear-Net-LDAP2 php-pecl-apc php-pgsql php-xml postfix python-beautifulsoup4 python-jinja2 python-ldap python-lxml python-netifaces python-setuptools python-sqlalchemy python-webpy spamassassin tmpwatch unrar unzip openldap apr apr-util apr-util-ldap arj cabextract clamav cronie cronie-anacron cyrus-sasl db4-cxx db4-devel ed file freeze gamin-python gdbm-devel glibc-devel glibc-headers httpd-tools ipset kernel-headers libXpm libc-client libicu libmcrypt libmnl libmspack libtool-ltdl libxslt logrotate lrzip lzo lzop mailcap mailx mysql mysql-libs nomarch p7zip p7zip-plugins perl perl-Archive-Tar perl-Archive-Zip perl-Authen-SASL perl-BerkeleyDB perl-Cache-FastMmap perl-Compress-Raw-Zlib perl-Compress-Zlib perl-Config-IniFiles perl-Convert-ASN1 perl-Convert-BinHex perl-Convert-TNEF perl-Convert-UUlib perl-Crypt-OpenSSL-Bignum perl-Crypt-OpenSSL-RSA perl-Crypt-OpenSSL-Random perl-DBD-MySQL perl-DBD-SQLite perl-DBI perl-Date-Manip perl-Digest-HMAC perl-Digest-SHA perl-Digest-SHA1 perl-Encode-Detect perl-Error perl-ExtUtils-MakeMaker perl-ExtUtils-ParseXS perl-GSSAPI perl-HTML-Parser perl-HTML-Tagset perl-IO-Compress-Base perl-IO-Compress-Zlib perl-IO-Multiplex perl-IO-Socket-INET6 perl-IO-Socket-SSL perl-IO-Zlib perl-IO-stringy perl-List-MoreUtils perl-MIME-tools perl-Mail-DKIM perl-MailTools perl-Module-Pluggable perl-Net-DNS perl-Net-LibIDN perl-Net-SSLeay perl-Net-Server perl-NetAddr-IP perl-Package-Constants perl-Pod-Escapes perl-Pod-Simple perl-Razor-Agent perl-Socket6 perl-Test-Harness perl-Text-Iconv perl-Time-HiRes perl-TimeDate perl-URI perl-Unix-Syslog perl-XML-Filter-BufferText perl-XML-LibXML perl-XML-NamespaceSupport perl-XML-SAX perl-XML-SAX-Writer perl-YAML-Syck perl-devel perl-libs perl-libwww-perl perl-version php-cli php-pdo php-pear portreserve postgresql-libs procmail python-babel python-cherrypy python-html5lib python-inotify redhat-logos rsyslog unzoo db4 db4-utils glibc glibc-common
参考文章:
https://docs.docker.com/articles/networking/
https://github.com/docker-build/iRedMail
https://hub.docker.com/search/?q=iRedMail&page=1&isAutomated=0&isOfficial=0&starCount=0&pullCount=0
http://john88wang.blog.51cto.com/2165294/1610504
http://dl528888.blog.51cto.com/2382721/1655142