Docker-基础
回顾hello-world
我们先来回顾一下hello-world的案例
下面是完整的流程图
1 | 先在本地查找是否存在hello-world镜像 |
下面介绍关于镜像和容器的命令
Docker镜像命令
搜索镜像
1 | [root@zhima ~]# docker search --help |
拉取镜像
1 | [root@zhima ~]# docker pull --help |
查看本地镜像
1 | [root@zhima ~]# docker images --help |
删除本地镜像
1 | [root@zhima ~]# docker rmi --help |
查看镜像层级构建信息
1 | [root@zhima ~]# docker history --help |
打标签
1 | [root@zhima ~]# docker tag --help |
Docker容器命令
创建一个容器
这里因为可选项太多,我只放一些常用的
1 | [root@zhima ~]# docker run --help |
1 | [root@zhima ~]# docker create --help |
删除一个容器
1 | [root@zhima ~]# docker rm --help |
查看容器
1 | [root@zhima ~]# docker ps --help |
停止容器
1 | [root@zhima ~]# docker stop --help |
运行容器
1 | [root@zhima ~]# docker start --help |
重启容器
1 | [root@zhima ~]# docker restart --help |
暂停容器
1 | [root@zhima ~]# docker pause --help |
取消暂停容器
1 | [root@zhima ~]# docker unpause --help |
查看容器的源数据
1 | [root@zhima ~]# docker inspect --help |
查看容器日志
1 | [root@zhima ~]# docker logs --help |
进入容器内部
1 | [root@zhima ~]# docker attach --help |
1 | [root@zhima ~]# docker exec --help |
一般我们都会使用docker exec -it containerId|containerName /bin/bash
进入容器
退出容器
1 | # 关闭当前的输出流,如果容器中没有其他输出流,容器就会自己关闭 |
如果容器中没有前台运行的command,则会自动关闭容器
查看容器开放端口
1 | [root@zhima ~]# docker port --help |
查看容器内进程信息
1 | [root@zhima ~]# docker top --help |
宿主机和容器内的文件复制
1 | [root@zhima ~]# docker cp --help |
命令总结
镜像的理解
什么是镜像
镜像是一种轻量级、可执行的独立软件包
它包含运行某个软件所需要的所有内容,包括代码,运行时(一个程序在运行或者在被执行的依赖)、库,环境变量和配置文件。
镜像加载原理
UnionFS
UnionFS (联合文件系统) 是一种分层、轻量级并且高性能的文件系统
它支持对文件系统的修改作为一次一次的提交做一层层的叠加
联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
BootFS
BootFS(Boot file system)主要包含Bootloader和Kernel
Bootloader主要是引导加载Kernel内核,Linux刚启动时会加载Bootfs文件系统
当Bootloader加载完成之后整个内核就都在内存中了
此时内存的使用权已由Bootfs转交给内核,系统也会卸载BootFS
RootFS
RootFS (root file system) ,在Bootfs之上。包含的就是典型Linux系统中的/dev, /proc, /bin, /etc等标准目录和文件。Rootfs就是
各种不同的操作系统发行版,比如Ubuntu , Centos等等。
docker的centos镜像为什么那么小?
对于一个精简的OS,RootFS可以很小,只包含一些最基本的命令、工具、库就可以了
当我们启动了一个容器,它底层可以直接使用宿主机已经加载好的Kernel
就不需要自己再虚拟一套环境,重新使用BootFS加载一个新的内核,大大节省了开销
Union 文件系统是Docker镜像的基础。
镜像可以通过分层来进行继承,基于基础镜像(没有父镜像) , 可以制作各种具体的应用镜像。
当我们拉取一个镜像
我们可以发现
该镜像是一层一层下载的而不是一整个下载的
这就符合了UnionFS的特性
前面几层是在我下载其他镜像的时候已经下载过了
就可以直接拿来使用,不需要再次下载,实现了资源共享,极大的节省了内存
查看镜像分层
1 | docker image inspect imageId|imageName |
特点
Docker镜像都是只读的
当使用命令启动了一个新的容器的时候
该镜像先被复制
接着一个新的可写层被添加到该复制后的镜像的顶层
这一层就是容器层
所以当我们新建了一个容器后,如果想将本次修改后的容器打包成一个新的镜像,就需要使用docker commit
命令
1 | [root@zhima volumes]# docker commit --help |
数据卷
数据卷技术,说白了,其实就是文件的同步
我们创建了一个MySQL的容器,我们不对其做任何措施
如果我们误删除或者有人恶意删除了该容器
那么里面保存的数据也就随之丢失了
这是一件十分恶劣的事情
所以为了防止这种事情
我们就需要使用一种技术,将容器内保存数据的目录挂载到宿主机上
这种技术就是数据卷技术
使用
这里我们部署一个MySQL来让大家明白如何使用卷技术
1 | # -v 宿主机目录:容器内目录 |
删除容器之后,宿主机中仍然保存着容器内的数据
1 | [root@zhima data]# docker stop mysql01 |
具名挂载和匿名挂载
1 | # 匿名挂载,我不指定宿主句的路径,指定容器内的路径 |
不管是具名挂载还是匿名挂载都是docker自动在/var/lib/docker/volumes
目录下创建文件夹
只不过具名挂载可以自己指定该文件夹的名字
数据卷容器
如何做到多个容器间数据共享呢?
那就需要使用数据卷容器技术,其实就是一个可选项,下面看使用
1 | [root@zhima home]# docker run --name mysql01 -v mysql_data:/usr/share/mysql -v mysql_config/etc/mysql/conf.d -p 49102:3306 -d -e MYSQL_ROOT_PASSWORD=123456 mysql |
mysql01就叫数据卷容器
mysql02、mysql03就会和mysql01的挂载是一样的
即mysql02和mysql03都和mysql01一样挂载到了宿主机的同个目录
/var/lib/docker/volumes/mysql_data
和/var/lib/docker/volumes/mysql_cofig
对数据卷的操作
1 | # 对卷的操作 |
Dockerfile
Dockerfile就是用来构建docker镜像的文件
1、Dockerfile中的保留关键词使用的时候都必须是大写
2、指令是从上到下执行的
3、#表示注释
4、每一个指令都会创建并提交一层镜像层
指令
Dockerfile中的指令
指令 | 说明 |
---|---|
FROM | 说明镜像使用的基础镜像 |
MAINTAINER | 设置镜像的作者 |
ADD | 构建镜像的时候复制文件到容器内 |
COPY | 构建镜像的时候复制文件到容器内 |
RUN | 设置容器的启动命令 |
ONBUILD | 设置镜像的ONBUILD指令 |
WORKDIR | 设置运行RUN CMD ENTRYPOINT COPY ADD指令的工作目录 |
USER | 设置运行RUN CMD ENTRYPOINT的用户名 |
STOPSIGNAL | 设置容器退出的时候的信号量 |
ARG | 设置编译镜像的时候加入的参数 |
LABEL | 设置镜像的标签 |
CMD | 编译镜像的时候运行的脚本 |
ENV | 设置容器的环境变量 |
EXPOSE | 设置镜像暴露的端口 |
ENTRYPOINT | 设置容器的入口程序 |
VOLUME | 设置容器的挂载卷 |
小试牛刀
自己制作一个带网络配置和vim的centos镜像
1 | FROM centos |
构建
构建命令
1 | [root@zhima home]# docker build --help |
构建镜像
1 | [root@zhima lizhi]# docker build -t mycentos:1.0 . |
启动容器
1 | [root@zhima lizhi]# docker run -it --name centos1 mycentos:1.0 |
CMD和ENTRYPOINT
我们来试一下构建这个Dockerfile,并运行
1 | FROM centos |
构建
1 | [root@zhima lizhi]# docker build -t mycentos . |
运行
1 | [root@zhima lizhi]# docker run -it --name "centos1" mycentos |
可以发现,进入容器之后,就执行了ls -a
命令
我们尝试一下在启动的时候加入一些参数
1 | [root@zhima lizhi]# docker run -it --name "centos2" mycentos -l |
我们发现容器并没有执行ls -al
,而是直接报错了
其实这就是CMD的特性,当我在启动容器的时候添加了一个CMD后
镜像中定义的CMD就被覆盖掉了
单独的-l
当然会报错了
我们来看一下使用ENTRYPOINT会怎么样
修改Dockerfile
1 | FROM centos |
重新构建
1 | [root@zhima lizhi]# docker build -t mycentos . |
运行容器
1 | [root@zhima lizhi]# docker run -it --name "centos1" mycentos -l |
可以发现,容器执行的是ls -al
,-l
指令被追加给了ENTRYPOINT定义的语句