您现在的位置是:首页 >学无止境 >Docker(一)网站首页学无止境
Docker(一)
Docker
Docker简述
传统虚拟机技术基于安装在主操作系统上的虚拟机管理系统,创建虚拟机(虚拟出各种硬件),在虚拟机上安装从操作系统,在从操作系统中安装和部署各种应用。这种方式占用资源很大并且步骤冗余。在此基础之上,Linux发展出了虚拟容器技术(LXC),不需要模拟出一个完整的操作系统,而是对进程与其他进程进行隔离。容器内的应用进程直接运行于宿主机的内核,不需要进行硬件虚拟,每个容器之间相互隔离,拥有独立的文件系统与隔离进程,可以区分计算资源。Docker应运而生,在操作系统层面上实现虚拟化,可以直接复用宿主机的操作系统,启动快,占用内存小。
Docker安装
在纯Linux环境下安装docker十分简单,使用apt或者yum安装后启动即可,但是在WSL2中安装需要注意,WSL中禁用了systemd命令,因此在安装Docker是需要使用原生方式安装,使用service方式启动
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh
$ sudo service docker start
Docker的基本组成
image镜像
- Docker中的镜像就是一个只读的模版文件,可以用来创建Docker容器,同一个Docker镜像文件可以创建很多个容器
container容器
- Docker利用容器来独立运行程序应用,容器就类似于一个虚拟化的运行环境。容器可以被创建、启动、停止、删除,每个容器之间都是相互隔离的,保证其中程序应用的独立性。
- 可以将容器看作是一个简易版的Linux环境和运行在其中的应用程序
repository仓库
- Docker仓库用于集中存放镜像文件,分为公开仓库和私有仓库两种形式,可以类比Maven仓库、github仓库
Docker架构
- 用户使用Docker Client与Docker Daemon建立通信,将操作命令请求发送给Docker Daemon中的Docker Server处理
- Docker Daemon作为Docker架构中的核心部分,提供
- Docker Server,用于接收Docker Client发送过来的命令操作请求
- Docker Engine,Docker Server接受到请求后发给Docker Engine执行Docker内部的一系列任务,每一项任务都是以Job的形式存在。
- Docker Registry。在Docker Engine中每一项Job执行的过程中,如果需要容器镜像,则使用Doocker Registry下载镜像。
- Docker Diver
- Graph Driver,通过Docker Registry下载的镜像会使用镜像管理驱动graph driver以graph的形式存储
- Network Driver,当处理Job的容器需要使用网络环境时,通过网络管理驱动network driver创建配置网络环境
- Exec Driver,当需要限制Docker容器运行组员或者执行指令时,通过指令执行驱动exec driver来完成
- LibContainer,是一个独立的容器管理包,Network Driver和Exec Driver都是通过其来对容器进行具体的指令操作
- Docker Container,Docker容器,具体的操作执行在此完成
使用Docker镜像加速
由于Docker Hub的网络连通性等问题,用户可以使用腾讯云或者阿里云等云服务提供商来进行Docker镜像加速。具体的操作此处不再赘述,腾讯云与阿里云的文档非常完整。
Docker常用命令
- 常用启动命令等在此忽略(sudo systemctl start docker等)
- 镜像层image命令
docker images
,用于列出本地宿主机上的镜像信息docker search 镜像名
, 在DockerHub中搜索镜像,可以使用--limit
限制显示数目docker pull 镜像名
,在DockerHub中下载拉取镜像文件docker system df
:查看镜像/容器/数据卷所占的空间docker rmi 镜像名/id
:在本地docker中删除某个镜像
- 容器层Container命令
只有当Docker本地存在镜像时,才可以对容器进行命令操作。docker run
:新建 + 启动容器,该指令存在可选指令项--name
为容器指定新名称-d
以守护方式(后台)运行容器并返回容器ID。当使用后台方式启动容器时,当容器执行的命令并不是那些一直挂起的命令,容器会自动退出。因此最佳解决方案是,以前台模式运行容器。-i
以交互模式运行容器,通常与-t
一起使用-t
为容器重新分配一个输入终端(前台运行容器,等待前台交互)-p ip:hostPort:containerPort
指定端口映射
docker ps
,显示当前所有正在运行的容器- 当容器正以交互模式运行时,可以使用两种方式来退出容器:
exit
退出并关闭容器ctrl + p + q
退出但不关闭容器
docker start
,启动已经停止的容器docker resatrt
,重启容器docker stop
,停止容器,docker stop -f
与docker kill
为强制停止容器docker rm
docker logs
,查看容器日志docker top
,查看容器内运行的进程docker inspect
,查看容器内部细节- 重新进入正在运行的容器内部可以使用以下两个方法
docker exec -it 容器id /bin/bash
,会创建一个新的进程供用户操作,并且用户在退出时只是关闭此终端,并不会影响容器的运行情况docker attach 容器id
,并不会创建新的进程,而是直接进入容器启动命令的终端,当exit退出终端时会导致容器的停止(后台运行)
docker cp 容器id:容器内文件路径 宿主机目的路径
,将容器内文件拷贝到宿主机上docker export 容器id > 文件名.tar
,将容器内容留做一个tar归档文件,用于导出为镜像文件,如docker export 6241563ac8fca > jarvis.tar.gz
docker import - 镜像用户/镜像名:镜像版本号
,如cat jarvis.tar.gz | docker import - jarvis/ubuntu:3.0
当然除此之外还有很多实用指令如docker commit
、docker diff
等,在此不进行赘述
Docker镜像
docker镜像是一种轻量级、可执行的独立软件包,包含了运行某个程序应用所需的所有内容。在使用时可以将应用程序和配置依赖等一起打包好形成一个可以交付的运行环境(代码、类库、环境变量、配置文件等),这个可交付的运行环境就是image镜像文件。
-
镜像分层
- UnionFileSystem:联合文件系统支持对文件系统的修改作为一次提交来进行一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Docker镜像的基础就是UnionFileSystem,镜像可以通过分层来进行继承,基于Base Image,可以制作各种各样的具体的应用级镜像。
- Linux系统在启动时会加载rootFileSystem,主要包含bootLoader和kernel。对于一个精简的os来说,rootFileSystem可以很小,只需要包括最基本的指令、程序库即可,Docker底层会直接使用宿主机的Kernel,因此Docker容器在这样的系统下创建会非常快速。
- 当docker容器启动时,一个新的可写容器层被加载到镜像的顶部,所有对容器的修改都只会发生在容器层,因为只有容器层是可写的,景象层包括最底层的bootFileSystem都是只读的。这样做保证了镜像层的完整以及容器层的多样,当我们需要将容器层的改动作为底层镜像存在时,可以使用
docker commit
将容器副本提交为一个新的镜像。如在Docker Hub上拉取到的Ubuntu镜像是不支持Vim指令的,我们可以在该镜像的容器中安装VIM,并且将该容器副本输出为一个新的镜像文件,这样就可以为我们所用了。
-
镜像存储
- 云服务提供商镜像仓库
在一些情况下,我们可以将自己创建的一些镜像发布到阿里云、腾讯云等云服务提供商支持的镜像仓库下,文档很详细,不赘述 - 使用Docker Hub提供的docker registry创建自己的私有镜像库
从docker hub上拉取docker registry到本地,处理好容器卷以及端口映射后启动docker registry容器,这样我们就可以使用docker push
将自己产出的镜像文件存放在该容器中了,使用docker pull
指令就可以将私有镜像仓库中的镜像拉取到本地运行。
- 云服务提供商镜像仓库
Docker容器数据卷
数据卷就是目录或者文件,存在于一个或者多个容器中,由docker挂载到容器,但是不属于UnionFS系统,因此可以绕过UnionFS提供一些用于持续存储或者共享数据的特性。数据卷的目的是实现数据的持久化,将完全独立于容器的生命周期,因此Docker不会在容器删除时删除其挂载的数据卷(类比Redis中的RDB或AOF文件,同时也可以类比VMWare中的共享文件夹),实现将Docker Container中的数据内容保存在宿主机的磁盘中。
- 如何运行一个带有容器卷存储功能的Docker Container实例:
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名或镜像ID
- 为什么需要添加
--privileged=true
在一些版本的Linux操作系统中,挂载目录被默认认为是不安全的行为,因此需要使用该参数扩大容器的权限解决挂载目录没有权限的问题。在使用了该参数后,Docker Container内的Root用户拥有了真正的Root权限,否则Container容器内的Root用户只是外部宿主机上的一个普通用户而已 - 使用了容器数据卷挂载后的优势
- 容器数据卷可以在多个容器之间共享复用数据
- 容器数据卷中的更改可以在容器对应目录中实时生效
- 容器数据卷中的更改不会包含在镜像的更新中
- 容器数据卷的生命周期会一直持续到没有容器使用它为止
- 可以使用
docker inpect
命令查看容器数据卷的挂载情况 - 可以为容器内的数据卷设置读写权限。在默认情况下,挂载的数据卷容器可以读写(rw),当为挂载数据卷添加readOnly(ro)模式时,容器对挂载数据卷中的内容就只能读取无法写入。
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:读写模式 镜像名或镜像ID
- 容器数据卷的继承与共享
当容器卷c1完成与宿主机数据卷的映射后,可以在其他容器上继承容器1的映射规则:
docker run -it --privileged=true --volumes-from c1 --name c2 ubuntu
Docker使用示例
-
使用Docker实现Mysql服务
- 从Docker Hub拉取mysql镜像
docker pull mysql:5.7
(基于方便哥们整了个Mysql tag 5.7版本的,Mysql8用户密码加密策略更新过 用起来有点烦) - 在Docker Hub上查询到启动该镜像容器实例的命令行启动容器,当然在处理前建议做好端口映射以及数据卷挂载
DockerHub示例指令:$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
- 端口映射和数据卷挂载
端口映射不再赘述,使用docker -p ip:Port:containerPort
即可完成
数据卷挂载是非常必要的操作,在没有进行数据卷挂载的mysql服务容器中数据将无法进行持久化存储。当该容器被删除销毁后,容器内的数据将不会保留,重新使用镜像启动容器也无法恢复数据。
需要进行的数据卷挂载操作:docker -v /data/mysql/log:/var/log/mysql -v /data/msyql/data:/var/lib/mysql -v /data/mysql/conf:/etc/mysql/conf.d
- 在外部可使用宿主机ip port映射连接容器内Mysql服务。Mysql中的字符集设置等行为哥们也不赘述,自己去处理,文档超多。
- 从Docker Hub拉取mysql镜像
-
使用Docker实现Mysql主从复制
使用Docker配置Mysql主从复制拢共分三步- 使用Docker创建Mysql主机
不赘述,使用这个命令docker run -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
创建,处理好数据卷挂载后,在宿主机上处理一下Mysql主机的配置后重启: - 使用Docker创建Mysql从机
同样的命令处理好端口映射以及数据卷挂载后,处理一下Mysql从机的配置 - 在Mysql主机中创建好从机用户、在Mysql从机中配置主从复制后开启主从复制
- 完成!
- 使用Docker创建Mysql主机
//mysql主机配置 my.cnf
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
//mysql从机配置 my.cnf
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
log-bin=mall-mysql-slave1-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
//在mysql主机中创建数据同步从机用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
//在Mysql从机中配置好主从复制后开启主从复制
change master to master_host='宿主机ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=617, master_connect_retry=30;
- 使用Docker配置redis集群
其实就是配置redis实例,只不过我们将实例配置在了docker中,详见redis集群相关
DockerFile
DockerFile是用来构建Docker镜像的文本文件,是由多条命令与参数组成的脚本。编写好DockerFile后,使用docker build
就可以构建出自定义镜像,使用docker run
就可以运行该镜像的容器实例。
- 构建DockerFile
- 基础
- 每条保留字指令都必须为大写字母并且跟随至少一个参数
- 指令从上到下顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
- DockerFile定义了进程需要的一切东西,包括执行代码或者文件、环境变量、依赖、运行环境、动态链接库、内核进程、服务进程、操作系统发行版等。
- DockerFile执行流程
- docker以基础镜像运行一个容器实例
- 针对每一条指令对容器做出修改
- 执行类似
docker commit
的操作提交一个新的镜像层 - docker基于刚提交的镜像运行一个新的容器
- 执行下一条指令直到所有指令都执行完成
- docker中各个组件的定位
- DockerFile作为程序应用的原材料
- Docker镜像为程序应用的交付物
- Docker容器为镜像交付物的运行台,涉及到部署运维
- 基础
- DockerFile常用保留字
FROM
第一条命令必须是FROM
,表示新镜像是基于那个基础镜像的,指定一个已经存在的镜像作为模版MAINTAINER
维护镜像的作者姓名与邮箱地址RUN
容器构建时需要运行的命令,分为两种格式(与CMD
不同,是在容器构建的时候运行)- shell格式
RUN <命令行指令>
,如RUN apt-get install vim
- exec格式
RUN ["可执行文件","参数1","参数2"]
,如RUN ["./test.php","dev","offline"]
,等价于RUN ./test.php dev offline
- shell格式
EXPOSE
当前容器对外暴露出的端口WORKDIR
指定在创建容器后,终端默认登陆进来的工作目录USER
指定以什么样的用户身份执行,默认是RootENV
用来在构建镜像过程中设置环境变量。这个环境变量那个在后续的任何RUN
指令中都可以使用(真·环境变量),当然在其他指令中也可以直接使用,如ENV MY_PATH /var/log/testPath
,WORKDIR $MY_PATH
ADD
将宿主机目录下的文件拷贝进入镜像,并且会自动处理URL和解压tar压缩包COPY
类似ADD
,可以将宿主机目录下的文件复制到镜像中指定目录下,如COPY src dest
VOLUME
数据容器卷,用于数据保存和持久化工作CMD
指定容器在启动后要干的事情。DockerFile中可以有多个CMD
指令,但是只有最后一个生效,并且CMD
会被docker run
后面的参数替换(与RUN
不同,是在容器运行docker run
的时候运行)- shell格式
CMD <命令>
- exec格式
CMD ["可执行文件","参数1","参数2"]
,在使用ENTRYPOINT
指定了指令后,使用CMD
指定具体的参数
- shell格式
ENTRYPOINT
同样是用来指定一个容器在启动时要运行的命令,但是ENTRYPOINT
不会被docker run
后面的参数覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT
指令指定的程序
ENTRYPOINT ["<executeable>","<params1>","<params2>"]
。可以与CMD
一同使用,一般是在变参的时候才会使用CMD
,这时CMD
相当于在给ENTRYPOINT
传参。如果DockerFile中存在多个ENTRYPOINT
指令,只有最后一个生效。如:
FROM nginx
ENTRYPOINT ["nginx","-c"]#定参
CMD ["/etc/nginx/nginx.conf"]#变参
当命令为docker run nginx:test 时,实际运行的是docker run nginx:test -c /etc/nginx/nginx.conf
当命令为docker run nginx:test -c /etc/nginx2.conf 时 实际运行的是 docker run nginx:test -c /etc/nginx2.conf
- DockerFile实际编写案例
目标:构建CentOS7 + vim + ifconfig + jdk8,构建成功后使用docker build -t 新镜像名:tag .
创建镜像
FROM centos
MAINTAINER zephyer<jarwu@zynga.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
EXPOSE 80
CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
- 虚悬镜像
仓库名、标签都是<none>
的镜像为虚悬镜像(dangling image)。当用户创建一个复用一个tag或者在构建镜像失败时,有可能会产生虚悬镜像。虚悬镜像已经失去了存在的价值,可以直接删除。可以使用docker images ls -f dangling=true
查看所有虚悬镜像,使用docker image prune
删除所有虚悬镜像。