前言
上学期寒假开始就稍微了解了下docker,无奈用的不是很多,也不是很懂
后来被强制性要求使用了几次docker(不得不说,安装配置问题一直令我很头大),就也算勉强能起来一个服务了
用了几次之后就决定系统的总结一下docker的使用,因为只是一些总结,更多的只是针对于我个人用的,不官方,不权威,不系统
Docker的三大概念
镜像(Images)
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
可以通过docker ps
来查看本机当中的镜像
容器(Container )
容器
和镜像
的关系类似于实例
与类
之间的关系
一个镜像可以起多个容器,并指定不同的参数
可以通过docker ps
查看当前运行的容器
仓库(Repository )
概念类似于git的仓库,我们可以从docker官方的仓库dockerhub中获取我们想要的镜像
利用<仓库名>:<标签>
的形式来获取指定仓库中的镜像,例如ubuntu:16.04
获取16.04版本的ubuntu
也可以将自己做好的镜像push到个人仓库中,供大家使用
Dockerfile
构建一个镜像一般使用Dockerfile来定制
类似于写入一个docker的配置文件,就可以根据配置的文件来生产特质的docker镜像
样例
下面是一个dockerfile的样例
1 | # 第一行写跟第1点中一样的基本镜像 |
里面注释也给的很清楚,就不做画蛇添足的解释了,然后来具体解释下一些命令
一些前置知识
docker commit
dockerfile中的每一条命令都会创建新的一层,然后执行命令,最后执行一次docker commit
保存这一层的修改,构成新的一层镜像。后面层的镜像都是在前一层的基础上进行改动
例如如下命令就会创建三层docker镜像,这样没有什么意义,并且浪费资源。而且最大的层数是有限制的
1 | RUN apt-get install -y php5-mysql |
正确的写法应该将改动合并到一条命令中
1 | RUN apt-get install -y php5-mysql php5-curl php5-gd |
还有一种情况就是我们想运行/var/www/html下的install.php文件
1 | RUN cd /var/www/html |
会发现其实根本没有运行这一条执行,因为新建的一层镜像执行目录又回归到了home目录中,所以前一个cd
命令可以说是无效的
正确的写法
1 | RUN cd /var/www/html && php install.php |
容器就是进程
这里先简单介绍一下CMD命令,其是用于启动容器时执行一些命令,一个dockerfile中只能有一个CMD命令,其用法如下
1 | shell 格式:CMD <命令> |
如
1 | CMD echo "hello world!" |
如果是用第一种,也就是shell格式时,在实际的执行过程中,会变成如下命令
1 | CMD ["sh","-c","echo hello world!"] |
然后就是docker中比较重要的两个概念
Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。
对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
比如之前我将CMD命令写为
1 | CMD service apache2 start |
可是真正运行的时候就会发现刚运行起来,容器就结束了
这就是因为在真正执行的时候这条命令被解释成了CMD ["sh","-c","service apache2 start"]
实际上的主进程是sh
,当service apache2 start
命令结束之后,sh
也就结束了。整个docker容器也跟随主进程的结束而一同结束了
写成如下格式即可
1 | CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] |
命令
主要介绍几个常用的,更详细的可以见官方文档
FROM
指定基础镜像。想要定制一个镜像就需要以另一个镜像为基础
docker官方提供了相当多的基础镜像,ubuntu、centos、debian,各种版本都有
以ubuntu16.04为基础镜像
1 | FROM ubuntu:16.04 |
RUN
用于执行命令,一般有如下两种格式
1 | shell 格式:RUN <命令> |
CMD
前面介绍过,格式和RUN一样,用于容器的启动命令
由于有时启动时需要执行较多的命令,而又只能执行一次CMD命令。一种较为通用的解决方法就是将命令写入start.sh中,CMD只要执行start.sh即可
COPY
复制文件,将本地的文件复制到docker镜像中
1 | COPY www /var/www/html |
将本目录下www文件夹放到/var/www/html中
ADD
更为高级的复制命令
若是压缩包会进行解压后进行复制,若是url则会去下载这个链接的文件后进行复制
格式和COPY一样
1 | ADD html.tgz /var/www |
ENV
用于设置环境变量
1 | ENV <key> <value> |
个人习惯于设置成非交互模式的
1 | ENV DEBIAN_FRONTEND noninteractive |
WORKDIR
指定工作目录,意为所执行的命令都是在当前目录下执行的
将工作目录切换到www目录下
1 | WORKDIR /var/www/html |
EXPOSE
声明端口,相当于当前容器暴露出这几个端口
1 | EXPOSE <端口1> [<端口2>...] |
一般作为web服务器会暴露80端口
1 | EXPOSE 80 |
容器操作
启动容器
主要是docker run
命令,然后添加一些执行的参数
直接运行
1 | docker run <镜像名> <命令> |
这样就能指定镜像运行,并且在运行时指定命令(会覆盖CMD命令)
1 | root@ubuntu:/home/kingkk# docker run ubuntu:16.04 echo "hello world!" |
当程序运行结束后,容器也会随之退出
进入终端
1 | docker run -it <镜像名> bash |
运行一个容器,并进入其bash终端
1 | root@ubuntu:/home/kingkk# docker run -it ubuntu:16.04 bash |
后台运行
更多时候使用docker是为了起一个服务,如web服务,我们更希望他在后台运行
1 | docker run -d -p 本机端口:容器端口 <镜像名> |
这也就可以在后台运行一个容器,-d
为在后台运行,-p
表示端口映射
不过要确保主进程一直在运行,否则会因为主进程的退出,容器也会退出
可以通过docker ps
查看正在运行的容器,及其一些信息
进入容器
1 | docker exec -it <容器ID> /bin/bash |
这样就可以进入正在运行的容器当中
1 | root@ubuntu:/home/kingkk# docker exec -it 7eb8 /bin/bash |
终止容器
终止就比较简单了
1 | docker stop <容器ID> |
这样就终止了一个正在运行的容器,终止成功并返回容器ID1
2root@ubuntu:/home/kingkk# docker stop 7eb8
7eb8
一个完整的示例
首先根据之前的样例中的Dockerfile写出一个完整的lamp的系统
- ubuntu 16.04
- php 7.0.30
- mysql 5.7.23
- apache2
建立了个docker目录,目录结构如下
1 | root@ubuntu:/home/kingkk/docker/test# tree ./ |
文件内容如下
Dockderfile
1 | FROM ubuntu:16.04 |
start.sh
1 | #!/bin/bash |
index.php
1 |
|
然后在当前目录生成test镜像
1 | docker build -t test . |
等待运行结束后docker images
即可查看到新生成的镜像
运行test镜像
1 | docker run -d -p 8888:80 test |
docker ps
就能查看到正在运行的容器状态
访问一下
OK 运行成功
一些常见问题
有时候启动不了可能还需要安装sudo apt-get install docker.io
会涉及到很多权限问题,需要切换成root权限来执行。无法获得root权限就要将用户添加到docker用户组
容器名和镜像名都可以用哈希值(或者哈希的一部分)代替
使用过windows和linux上的docker,windows上会出现一些小问题,如\r\n
和\n
,而且和虚拟机啊不能共存。所以推荐在linux上用docker。(mac没钱买不起。。。
可以更新下docker源,会提示很多速度
在测试部署的时候可以使用-v参数
1 | docker run -d -p 80:80 -v ./www:/var/www/html/ imagename |
相当于将当前目录下www目录和容器中/var/www/html/目录相关联,当你本地文件发生变化时,容器中的文件也会随之变化
有时候会多出很多\<none>镜像,这种镜像被称为悬空镜像,可以用docker image prune
删除
Reference Link
https://yeasy.gitbooks.io/docker_practice