Docker简介
Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack 集群和其他的基础应用平台。
Docker用于场景
web应用的自动化打包和发布;
自动化测试和持续集成、发布;
在服务型环境中部署和调整数据库或其他的后台应用;
从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境。
安装docker
# yum install docker-io
# systemctl start docker.service
# systemctl enable docker.service
# ifconfig
宿主机出现 docker0 的虚拟网络接口。
docker 代理网络设置
# vim /etc/sysconfig/docker
HTTPS_PROXY=http://proxy.sinaabc.com:3128
HTTP_PROXY=http://proxy.sinaabc.com:3128
# docker version //查看docker的版本号,包括客户端、服务端、依赖的Go等
# docker info //查看系统(docker)层面信息,包括管理的images, containers数等
镜像获取使用
镜像可以看作是包含有某些软件的容器系统,比如ubuntu就是一个官方的基础镜像,很多镜像都是基于这个镜像“衍生”,该镜像包含基本的ubuntu系统。再比如,hipache是一个官方的镜像容器,运行后可以支持http和websocket的代理服务,而这个镜像本身又基于ubuntu。
搜索镜像
# docker search ubuntu12.10
下载镜像
# docker pull ubuntu12.10x64
查看镜像
# docker images 列出images
# docker images -a 列出所有的images(包含历史)
# docker images --tree 显示镜像的所有层(layer)
# docker rmi <image ID> 删除一个或多个image
创建容器
# docker run chug/ubuntu12.10x64 /bin/echo hello world
hello world
创建运行不进入交互
# docker run -itd <image> /bin/bash
查看容器
docker ps :列出当前所有正在运行的容器
docker ps -l :只显示最新创建的容器,包括非运行的。
docker ps -a :显示所有容器。 默认只显示运行容器。
docker ps -q :列出最近一次运行的container I D
再次启动容器
docker start/stop/restart <container> 开启/停止/重启container
docker start [container_id] 再次运行某个container (包括历史container)
docker attach [container_id] 连接一个正在运行的container实例(即实例必须为start状态,可以多个窗口同时attach 一个container实例)
docker start -i <container> 启动一个container并进入交互模式(相当于先start,在attach)
进入容器 (进入前首先要启动容器)
docker exec -it 19ee6bc10189 /bin/bash
映射 HOST 端口到容器
方便外部访问容器内服务,host_port 可以省略,省略表示把 container_port 映射到一个动态端口。
docker run -i -t -p <host_port:container_port>
docker run -i -t -d -p 1200:11211 niexiaohu/centos-memcached
删除容器
docker rm <container...> 删除一个或多个container
docker rm `docker ps -a -q` 删除所有的container
docker ps -a -q | xargs docker rm 同上, 删除所有的container
检查运行中的镜像
docker inspect container_id
发布docker镜像
docker push docker.sinaabc.com/centos6
保存对容器的修改
docker commit [container_id] chug/nginx
通过容器生成新的镜像
使用docker commit <container-id> <image-name> 命令可以把一个正在运行的容器变成一个新的镜像, repo:tag可选。
# docker commit d0fd23b8d3ac chug/ubuntu12.10x64_2
daa11948e23d970c18ad89c9e5d8972157fb6f0733f4742db04219b9bb6d063b
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
chug/ubuntu12.10x64_2 latest daa11948e23d seconds ago 270.3 MB
chug/ubuntu12.10x64 latest 0b96c14dafcd months ago 270.3 MB
持久化
持久化容器
export命令用于持久化容器
docker export <container_id> > /tmp/export.tar
持久化镜像
Save命令用于持久化镜像
docker save image_id > /tmp/save.tar
导入持久化container
# cat /tmp/export.tar | docker import - export:latest
导入持久化image
# docker load < /tmp/save.tar
对image打tag
# docker tag daa11948e23d load:tag
其它操作
docker logs $CONTAINER_ID 查看docker实例运行日志,确保正常运行
docker inspect <image|container> 查看image或container的底层信息
docker build <path> 寻找path路径下名为的Dockerfile的配置文件,使用此配置生成新的image
docker build -t repo[:tag] 可以指定repo和可选的tag
docker build - < <dockerfile> 使用指定的dockerfile配置文件,docker以stdin方式获取内容,使用此配置生成新的image
docker port <container> <container port> 查看本地哪个端口映射到container的指定端口,其实用docker ps 也可以看到
docker文件存放目录
Docker实际上把所有东西都放到 /var/lib/docker路径下了。
# ls -F
containers/ devicemapper/ execdriver/ graph/ init/ linkgraph.db repositories-devicemapper volumes/
containers目录当然就是存放容器(container)了,graph目录存放镜像,文件层(file system layer)存放在graph/imageid/layer路径下,这样我们就可以看看文件层里到底有哪些东西,利用这种层级结构可以 清楚的看到文件层是如何一层一层叠加起来的。
查看root密码
docker容器启动时的root用户的密码是随机分配的。所以,通过这种方式就可以得到容器的root用户的密码了。
docker logs 5817938c3f6e 2>&1 | grep 'User: ' | tail -n1
关于 Dockerfile
Dockerfile 是一个镜像的表示用来描述构建镜像的步骤,Docker可以从文本Dockerfile读取指令作为构建步骤并自动生成最终镜像
1.使用Dockerfile
指定一个存储库和标签 -t shykes/myapp .
$ sudo docker build -t shykes/myapp .
2.格式
INSTRUCTION arguments (指令 参数 )
指令是不区分大小写的,建议指令都大写,更容易区别于参数, 第一个指令必须“FROM” 以指定构建的基础镜像。
以 '#' 开始作为一个注释。如:
# Comment
RUN echo 'we are running some # of cool things'
3. 指令
FROM
, MAINTAINER
, RUN
, ENTRYPOINT
, USER
, ESPOSE
, ADD
3.1 FROM
语法: FROM <image> 或 FROM <image>:<tag>
Dockerfile第一个指令必须是 FROM,FROM 可以出现多次在单个Dockerfile为了创建多个镜像,FROM 后面为基础镜像, 如:
FROM ubuntu
3.2 MAINTAINER
语法: MAINTAINER <name>
MAINTAINER命令用来指定维护者的信息说明:
MAINTAINER Guillaume J. Charmes <guillaume@dotcloud.com>
3.3 RUN
RUN命令会在上面FROM
指定的镜像里执行任何命令,然后提交(commit)结果,生成新的图层,提交的镜像会在后面继续用到。
RUN两种格式:
1、RUN <command> # 运行一个shell命令
RUN apt-get install -y openssh-server
3.3 RUN
RUN命令会在上面FROM
指定的镜像里执行任何命令,然后提交(commit)结果,生成新的图层,提交的镜像会在后面继续用到。
RUN两种格式:
1、RUN <command> # 运行一个shell命令
RUN apt-get install -y openssh-server
2、exec 执行方式
语法:RUN ["executable", "param1", "param2" ... ]
RUN ["/bin/bash", "-c", "echo hello"]
3.4 CMD
CMD主要用于容器启动时执行启动服务的命令。Dockerfile 只能有一个CMD,如果有多个CMD则最后的CMD生效。
CMD有三种方式:
1、CMD ["executable","param1","param2"] (使用 exec
执行,推荐方式)
CMD ["/bin/bash", "-c", "echo hello"]
2、 CMD ["param1","param2"] (给 ENTRYPOINT
提供参数 ) 如:
FROM ubuntu
CMD ["-D","--help"]
3、 CMD command param1 param2 ( 以”/bin/sh -c”方法执行命令) 如:
CMD echo "This is a test." | wc -
3.5 EXPOSE
语法:EXPOSE <port> [<port>...]
如:Nginx使用80端口,把这个端口暴露在外,这样容器外可以看到这个端口并与其通信。
EXPOSE
3.6 ENV
ENV指令设置环境变量值
语法: ENV <key> <value>
ENV LANG en_US.UTF-
ENV APP_DIR /app
3.7 ADD
复制新文件,并将它们添加到容器的文件系统路径
语法: ADD <src> <dest>
ADD ./start.sh /root/start.sh
<src>
是相对被构建的源目录的相对路径
,可以是文件或目录的路径,也可以是一个远程的文件url
<dest>
是container中的绝对路径.
COPY 作用类似于ADD
语法: COPY <src> <dest>
。
复制本地主机的 <src>
(为Dockerfile所在目录的相对路径)到容器中的 <dest>
。
当使用本地目录为源目录时,推荐使用 COPY
。
3.8 ENTRYPOINT
意思是进入点,容器启动时执行命令,一个Dockerfile中只能有一条ENTRYPOINT命令,如果多条则只执行最后一条ENTRYPOINT.
ENTRYPOINT、CMD,一般两者可以配合使用,CMD提供默认参数,比如:
ENTRYPOINT ["/usr/sbin/sshd"]
CMD ["-D"]
ENTRYPOINT 和 CMD的不同点在于执行docker run时参数传递方式,CMD指定的命令可以被docker run传递的命令覆盖:
1、CMD 指令:
CMD ["echo"]
运行 :
# docker run container_name echo foo
结果打印出: foo
2、ENTRYPOINT指令:
ENTRYPOINT ["echo"]
运行 :
# docker run container_name echo foo
结果打印出:echo foo
3.9 VOLUME
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库或需要保存的数据
VOLUME ["/data"]
3.10 USER
指定使用哪个用户或uid运行镜像
USER daemon
3.11 WORKDIR
配置RUN
, CMD
, ENTRYPOINT
命令设置当前工作路径
WORKDIR /path/to/workdir
语法: ONBUILD [INSTRUCTION]
ONBUILD ADD . /app
ONBUILD 在生成当前docker镜像的时候不生效,在子镜像生效;ONBUILD 在产品发布时起着非常重要的作用。
如:
A镜像中有ONBUILD指令,在构建A镜像时ONBUILD指令不执行;B镜像FROM A ,在构建B镜像时 ONBUILD 指令开始执行;
4. Dockerfile Examples
1.官方实例:
'#' 为注释符,这里Dockerfile构建4个镜像,写好Dockerfile文件后就可以在该目录下运行 docker build . 命令了(可以用 -t 参数指定tag)
# Nginx
#
# VERSION 0.0. FROM ubuntu
MAINTAINER Guillaume J. Charmes <guillaume@dotcloud.com> # make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update RUN apt-get install -y inotify-tools nginx apache2 openssh-server
# Firefox over VNC
#
# VERSION 0.3 FROM ubuntu
# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update # Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get install -y x11vnc xvfb firefox
RUN mkdir /.vnc
# Setup a password
RUN x11vnc -storepasswd ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc' EXPOSE
CMD ["x11vnc", "-forever", "-usepw", "-create"]
# Multiple images example
#
# VERSION 0.1 FROM ubuntu
RUN echo foo > bar
# Will output something like ===> 907ad6c2736f FROM ubuntu
RUN echo moo > oink
# Will output something like ===> 695d7793cbe4 # You'll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
# /oink. 示例2: 创建 一个运行ssh server镜像
FROM centos6
# build ssh
MAINTAINER niexiaohu niexiaohu@yolo24.com
RUN echo "root:123456" | chpasswd
RUN yum install openssh-server
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
ENTRYPOINT ["/usr/sbin/sshd"]
CMD ["-D"]
# CMD /usr/sbin/sshd -D
EXPOSE
容器内启动多个服务程序
在一个 container中部署两个以上服务程序的情况和需求上,因为Dockerfile只允许执行一个CMD,这种情况下需要借助supervisor进程监控管理程序来启动和管理container 内的多个程序。
1、创建Dockerfile:
FROM centos:centos6 MAINTAINER xxx xxxx "xxxx@hotmail.com" RUN rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
RUN yum install -y openssh-server sudo mysql-server mysql supervisor
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config RUN useradd admin
RUN echo "admin:admin" | chpasswd
RUN echo "admin ALL=(ALL) ALL" >> /etc/sudoers RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN mkdir /var/run/sshd RUN /etc/init.d/mysqld start &&\
mysql -e "grant all privileges on *.* to 'root'@'%' identified by 'letmein';"&&\
mysql -e "grant all privileges on *.* to 'root'@'localhost' identified by 'letmein';"&&\
mysql -u root -pletmein -e "show databases;" RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisord.conf EXPOSE
CMD ["/usr/bin/supervisord"]
2、在Dockerfile所在目录下创建supervisord.conf文件
[supervisord]
nodaemon=true [program:sshd]
command=/usr/sbin/sshd -D [program:mysqld]
command=/usr/bin/mysqld_safe
3.在Dockerfile 当前目录执行命令生成image.
# sudo docker build -t myserver .
完整部署 Web 应用
1、创建maven-demo和maven-repo目录用作docker volume,这样Maven创建的项目会持久化在maven-demo目录下,maven的local repository持久话在maven-repo目录下。
$ mkdir maven-demo maven-repo
2、运行maven docker新建一个Maven项目
$ docker run -it --rm --name maven-demo -v "$PWD"/maven-demo:/usr/src/maven-demo -v "$PWD"/maven-repo/:/root/.m2/repository -w /usr/src/maven-demo maven:3 mvn -B archetype:generate -DgroupId=com.aliyun.demo -DartifactId=hello-world -DarchetypeArtifactId=maven-archetype-webapp
运行成功后,可以看到项目目录结构如下:
hello-world
|---pom.xml
|---src
|---main
|---resource
|---webapp
|---WEB-INF
| |---web.xml
|---index.jsp
3、构建Maven项目
$ docker run -it --rm --name maven-demo -v "$PWD"/maven-demo/:/usr/src/maven-demo -v "$PWD"/maven-repo/:/root/.m2/repository -w /usr/src/maven-demo/hello-world maven mvn package
构建成功后,hello-world目录下多了一个target目录,包含hello-world.war文件。
4、Docker镜像打包:使用Docker运行Java Web应用,推荐基于Tomcat的Docker容器来打包、运行您的Java应用,选择Tomcat的Docker基础镜像上构建应用镜像。
Dockerfile如下所示:
FROM tomcat:
ADD maven-demo/hello-world/target/hello-world.war /usr/local/tomcat/webapps/
CMD ["catalina.sh", "run"]
5、打包镜像
$ docker build -t docker.sinaabc.com/maven-demo-hello-world .
6、上传到registry
$ docker push docker.sinaabc.com/maven-demo-hello-world
7、另外一台机器上获取镜像
$ docker pull docker.sinaabc.com/maven-demo-hello-world
8、运行Docker镜像
$ docker run -d -p 8080:8080 docker.sinaabc.com/maven-demo-hello-world
打开浏览器访问 http://hostip:8080/hello-world/ 将会看到 Hello World! 的输出,表示编译的hello-world war 包已经成功使用 Docker 运行起来了。
数据容器
FROM tomcat:
ADD your.war /usr/local/tomcat/webapps/
使用这样的Dockerfile构建出数据容器,并将它的volume与Tomcat容器共享。
$ docker build -t app-image .
$ docker create -d -v /usr/local/tomcat/webapps/ --name app app-image true
$ docker run -d --volumes-from app tomcat:8
由于系统一定会把共享volume的容器调度运行在同一台宿主机上,这样可以保证正确运行。然而,由于共享volume的容器只能被调度到同一台宿主机上,这样会限制系统的可伸缩性。