Docker初探
一.安装DockerCE
1.为啥我要安装DockerCE呢?其实我也不明白,稀里糊涂就装了CE版本:可以参考官方文档(https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#extra-steps-for-aufs)
另外我安装Docker的系统是ubuntu16.04
$ sudo apt-get update
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce
经过以上几步,恭喜你,DockerCE已经安装完成了!!!
下面就是测试:
$ sudo docker run hello-world
如果安装正确,那么这条命令将从Docker官网上下载hello-world镜像并在本地运行。
二.我理解的Docker
Docker只是一个用命令行来实现的虚拟机。相较于WM,他的功能更加强大一点,可能和virtualbox相似(我没用过VB,不过VB创建虚拟机好像也可以用命令行)。不过Docker-machine、docker-compose、docker-swarm提供了比VM和VB更加强大的功能。值得一提的是,一般我们所讲的Docker均是指Docker-engine,本篇文章讲的Docker指的是docker-engine。等作者开始研究其他三个的时候再另发博客。
三.images、container
VM以及VB在创建虚拟机时需要使用iso镜像文件,然而docker不需要或者说他已经把镜像文件都传到了官网上,我们只需要从Docker官网下载即可。
1.Images
首先是创建images,创建images有两种方法,一种是使用docker pull。比如说我们要使用docker版的ubuntu系统,就可以使用docker pull ubuntu。更多的镜像可以再https://hub.docker.com/中找到。另一种方法时使用dockerfile文件,使用过程中更倾向于使用后者创建docker image。至于dockerfile的用法网上有很多例子。dockerfile其实很简单,有兴趣的可以网上学习一下,这里简单给一个安装了c++以及boost运行环境的dockerfile:
FROM ubuntu:16.04
MAINTAINER Uncle_Orange <250316792@qq.com>
LABEL description="ubuntu C++ build environment."
RUN apt-get update && apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
ADD sources.list /etc/apt/
RUN apt-get update && apt-get install -y \
# gcc \
# clang \
# cmake \
# libgtest-dev \
# libgoogle-glog-dev \
# libboost-all-dev \
# g++ `#Fb folly deps` \
# automake \
# autoconf \
# autoconf-archive \
# libtool \
# libboost-all-dev \
# libevent-dev \
# libdouble-conversion-dev \
# libgoogle-glog-dev \
# libgflags-dev \
# liblz4-dev \
# liblzma-dev \
# libsnappy-dev \
# make \
# zlib1g-dev \
# binutils-dev \
# libjemalloc-dev \
# libssl-dev \
# libiberty-dev\
build-essential\
libboost-all-dev\
cmake\
iputils-ping\
net-tools\
nano
ENV LIBRARY_PATH=/libs
ENV CPLUS_INCLUDE_PATH=/libs/include
RUN mkdir /src
RUN mkdir /build
WORKDIR /build
CMD ["/bin/bash"]
创建镜像命令:
进入到dockerfile所在的文件夹,然后注意后面有'.'表示当前目录。这样就有自己的镜像了。
docker build -t uo/ubuntu:v1.0 .
2.container
创建容器:
docker run。具体参数不贴了,可以自己-h查看一下。
四.容器端口映射
在https://docs.docker.com/get-started/part2/上有一个使用dcoker+python实现的一个简单网页,可以自己按照教程实现一下。该例子在创建容器的时候使用了
docker run -p 4000:80 friendlyhello
将容器作为web服务端,80端口映射到主机的4000端口上。并且在dockerfile中加入了expose 80这个命令(这个命令实现和docker run -p同样的效果?还是必须和docker run -p配合使用?这个还没试过,有兴趣的朋友可以试一下,然后最好能告诉一下结果)总之在使用上述配置和命令后能从作者的主机直接访问web服务器,这也是官方例子给的结果。
那么下面就进入正题了,如何在没有配置的情况下任然能联通呢?因为在开发过程中很多情况下多需要临时增加端口是很常见的情况,网上找了两种方法
Docker 给运行中的容器添加映射端口方法1
-
获得容器IP
$ docker inspect `container_name` | grep IPAddress
比如我的容器叫
mysqlserver
么就输入下列代码来获取该容器的ip地址$ docker inspect mysqlserver | grep IPAddress
执行完之后会发现我的
mysqlserver
docker容器的ip地址为192.168.0.2
-
iptables转发端口
比如我将容器的3306端口映射到主机的37221端口,那么ip对应就写入我的docker容器IP即可
iptables -t nat -A DOCKER -p tcp --dport 37221 -j DNAT --to-destination 192.168.0.2:3306
Docker 给运行中的容器添加映射端口方法2
-
提交一个运行中的容器为镜像
$ docker commit containerid foo/live
-
运行镜像并添加端口
$ docker run -d -p 8000:80 foo/live /bin/bash
对比官方给的web服务器的例子,使用iptables -t nat -nL以及iptables -t filter-nL查看防火墙可以看到,其实就是增加了几条规则。或者说docker-p参数以及dockerfile中的expose关键字其实就是在使用iptables增加规则。
知道了这个就好办了,下面是楼主的解决办法:
sudo iptables -t filter -A DOCKER -p udp -d 172.17.0.2 --dport 9876 -j ACCEPT
sudo iptables -t nat -A DOCKER -p udp --dport 9876 -j DNAT --to-destination 172.17.0.2:9876
sudo iptables -t nat -A DOCKER -p udp --dport 9876 -j DNAT --to-destination 172.17.0.2:9876
没错,就只有两行!!!!这两行试了做好久,
同时贴上几个相关帖子:
http://blog.csdn.net/u011350541/article/details/50781040
http://blog.csdn.net/cooling88/article/details/51040054
https://www.cnblogs.com/kevingrace/p/5865792.html
至于验证嘛,作者写了一个udp发信信息的服务端,传到了所创建的uo/ubuntu中,然后从主机上发送udp消息。可以看到所创建的容器能正确接收到信息。
顺便在这里提一下作者的网络拓扑:
作者主机:192.168.10.2
安装docker的虚拟机:192.168.10.100
容器IP:172.17.0.2
作者直接向192.168.10.100:9876发信udp包,在172.17.0.2中能正确接收信息。相当于192.168.10.100做了一次nat转换(截图就不截了)