Docker 入门快速上手指南
为什使用Docker?
为什么要使用Docker?就个人而言,Docker能提供的最大便利在于这种技术面对程序环境迁移时所表现的卓越性。
这种性能使得我们不必在分享代码或项目合作、交接时附带一长串的环境配置指南进行版本限制和扩展描述;也不必再特意记录自己对现有环境的配置改变,以免下次系统迁移时手足无措;更为重要的是,Docker在提供以上解决方案的同时没有把解法变得复杂,相反的,它提供了一种更快、更容易的方式。
Docker独到的对增量和文件层的应用,使得镜像下载、共享&隔离、版本控制等问题的解决方法变得格外优雅。有兴趣的读者可以参考「循序渐进学Docker」这本书。
下载&安装
下载
访问下面的网址,从菜单的GetDocker中选择适合的版本进行下载。
https://www.docker.com/
安装
Mac和Windows中都可以使用桌面版傻瓜式安装,而Centos中的安装会受限于系统内核版本,可查看参考链接。
安装完成后,可以通过以下方式查看Docker版本:
docker--version
更改镜像源
国内访问官方镜像的速度较慢,可以选用国内的镜像源,这里给出DaoCloud和阿里云的镜像源,镜像源更换方法在以下网址中都有说明:
DaoCloud:https://www.daocloud.io/mirror
AliCloud:https://cr.console.aliyun.com/#/accelerator
镜像市场
可以从以下网址中搜索需要的镜像:
官方:https://store.docker.com/
DaoCloud:http://hub.daocloud.io/
AliCloud:https://dev.aliyun.com/
名词解释
- 镜像:从镜像市场中下载的即为镜像,可以理解为容器的模板。
- 容器:应用程序运行的环境,容器的创建依赖于某一镜像。注意,容器不是镜像的拷贝,容器只是在镜像之上建立了一层读写层,用以覆盖容器内对镜像配置、文件的修改。采用这一方式可以避免因频繁的镜像复制而导致的资源浪费。具体可以参考相关书籍或博客。
镜像与容器
镜像的搜索与获取
搜索镜像
可以在安装了Docker的机器上使用以下指令搜索镜像,不过还是建议通过访问镜像商店的方式搜索。注意,$mirror-name需要替换为想要搜索的镜像名。
dockersearch$mirror-name
获取镜像
可以使用以下指令拉取镜像到本地,其中冒号后的$tag为镜像的版本标签,如果省略冒号及之后的内容,则为下载最新版本即:latest。版本标签信息可以在镜像市场中查找到。
dockerpull$mirror-name:$tag
注意,若下载的镜像携带有版本标签,则之后对这一镜像的使用都需要携带版本标签,否则会因为版本不同而再次下载。
镜像的查看与删除
查看镜像
查看所有镜像可以使用:
dockerimages
也可通过以下方式查看单个镜像:
dockerimages$mirror-name
删除镜像
我们可以通过以下方式删除镜像,但此时需要保证没有容器使用这一镜像:
dockerrmi$mirror-name
查看容器
查看已启动的容器
dockerps
查看全部容器
dockerps-a
查看容器日志
采用以下方法可以查看容器的操作历史和输出:
dockerlogs$container-name
启动容器
生成容器
可以通过以下方式生成一个基于某一镜像的容器,注意,如果宿主机中没有该镜像则会先进行下载。务必注意镜像标签是否正确。
dockerrun$mirror-name:$tag
使用这一命令会使得容器在创建后自动启动。
给容器添加自定义名字
通过dockerps-a可以看到容器的ID和name,这两者都可以作为后续对容器删除、启动、关闭及设置等操作的标识。使用ID时,只需输入ID的前几位即可(能与其他容器区分)。
Docker会为其随机生成64位长度的字符串作为ID,当然,我们也可以通过如下方式手动指定容器的名字,其中$container-name即为指定的容器名。
dockerrun--name$container-name$mirror-name
启动容器
dockerstart$container-name
关闭容器
dockerstop$container-name
以交互方式创建容器
可以通过以下方式,以交互的方式创建容器,当然也可以在$mirror-name的前面加上--namexxx来指定容器的名字,在交互模式中,可以输入exit退出:
dockerrun-it$mirror-name
以后台运行方式创建容器
我们可以使用-d操作使容器在后台运行:
dockerrun-d$mirror-name
容器状态问题
容器在启动后,如果没有活动的前台进程,容器会自动关闭。若要保持容器启动状态,可以强制其执行一个前台进程。
可以用以下方式创建一个不自动关闭的centos镜像:
dockerrun-it--namemycentoscentos dockerstartmycentos //此时可以看到该容器没有自动关闭 dockerps
容器执行操作
我们可以通过以下方式对已经启动的容器执行一些操作,其中$container-name可以是容器的名字,也可以是容器的ID:
dockerexec$container-nameecho"hello"&&echo"world"
也可以通过以下方式进入交互模式:
docekrexec-it$container-namebash
其中,&&是起到操作间连接的作用。此外,我们也可以在创建的容器的时候就使其执行一些操作:
dockerrun$mirror-nameecho"helloworld"
查看容器详情
通过以下方式可以查看容器的详细信息,这些信息是采用JSON的格式展现的:
dockerinspect$container-name
删除容器
可以在rm之后加入一个或多个容器名或容器ID进行批量删除。
dockerrm$container-name-1$container-name-2...
可以使用以下方法删除全部容器:
dockerrm$(dockerps-aq)
Docker网络
网络类别
查看网络类别
网络的类别为none,host,bridge三种,可以通过以下方式查看:
dockernetworkls
none型网络
顾名思义,此类网络表示容器为独立个体,不与外部通信。
host型网络
此类网络表示该容器与宿主机(安装Docker的机器)共享网络。
bridge型网络
这是容器的默认网络类型,网桥模式意味着容器间可以互相通信,而对外的通信需要借助宿主机,这一形式通常表现为端口号的映射。
查看网络类别详情
dockernetworkinspect$network-name
通过这种方式可以查看JSON格式的网络类别,在Containers条目中可以看到使用当前网络类型的容器列表,注意Containers中只会显示那些已经启动的容器。
创建网络
可以通过以下方式创建一个网络,其中,$network-driver表示网络类别,即none或bridge或host,而$network-name为自定义的网络名:
dockernetworkcreate--driver$network-driver$network-name
如果省略--driver$network-driver则默认创建bridge类型的网络。
为容器指定网络
我们可以创建自定义的网络环境,并将一些容器放入这一网络内,以此管理容器间的网络连通情况。这种局域网网段的模拟实际是由内部DNS实现的。以下罗列将容器添加或移除到某一网络中的方法。
将容器添加进某一网络
可以通过以下方式将容器$container-name加入$network-name网络中。注意,一个容器可以属于多个网络。
dockernetworkconnect$network-name$container-name
之后,当容器启动时,我们就可以在dockernetworkinspect$network-name的Containers中看到这一容器了。
将容器从某一网络中移除
dockernetworkdisconnect$network-name$container-name
在容器生成时指定网络
我们也可以在容器生成时指定网络,使用如下方法:
dockerrun--network$network-name$mirror-name
测试网络连通情况
我们可以通过以下方式查询到容器的IP地址:
- 在容器交互模式中使用ipaddr;
- 使用dockerinspect$container-name
- 使用dockerinspect$container-name|grepIPAddress
之后可以使用ping指令测试容期间的网络连通情况。没有ping命令的容器需要安装iputils。
删除网络
dockernetworkrm$network-name
Docker存储
有时,我们需要将容器的部分存储映射到宿主机器件中,以便对配置文件、日志文件、数据文件等进行备份或统一管理。
指定数据卷
我们可以在创建时,将系统的某一目录指定为容器某一目录的数据卷,其中--volume可以使用-v缩写:
dockerrun--volume/my/mac/dir:/container/dir$mirror-name
此时,容器内部的/container/dir将与宿主机的/my/mac/dir形成映射。
当然,我们也可以将文件与文件映射起来。
dockerrun--volume/my/mac/file:/container/file$mirror-name
在指定数据卷时,可以省略宿主主机目录,此时Docker会自动指定一个主机空间用以映射:
dockerrun--volume/container/dir$mirror-name
此外,还可以选择只读方式,这样文件或目录的修改就只能在宿主机中进行了。只需添加:ro即可:
dockerrun--volume/my/mac/dir:/container/dir:ro$mirror-name
我们可以通过dockerinspect$container-name,并在Mounts中看到数据卷的详细情况。
查看数据卷
我们可以通过以下指令查看数据卷的情况:
dockervolumels
当容器被删除时,主机上的数据卷并不会被删除,此时可以通过以下指令查看那些没有容器使用的数据卷,注意,这里只会显示那些由Docker自动指定的数据卷,即没有手动指定主机映射目录的数据卷:
dockervolumels-fdangling=true
顺便,如果需要在删除容器时一并删除数据卷,可以使用以下指令:
dockerrm-v$container-name
数据卷的继承
有时我们可能需要在创建容器时,选择该容器的数据卷与之前的某容器相同,比如在面对多容器共享项目目录空间这一需求时。此时我们可以通过以下方式实现:
dockerrun--volumes-from$container-name$mirror-name
数据卷的删除
可以使用如下方式删除数据卷,其中$volume-id可以通过dockervolumels查看:
dockervolumerm$volume-id
给已创建时的容器添加数据卷
容器一旦创建后,再添加数据卷映射会比较麻烦。
而且,这里并不建议这么做,建议的做法是将容器提交为镜像后,以此镜像再次创建容器。
Docker端口
绑定端口
我们可以将容器的端口绑定到主机的某一端口上,已完成某些应用的需求,如将主机的12345端口绑定到容器的80端口上,这样我们对localhost:12345的访问就相当于对容器80端口的访问。
通过以下方式可以实现端口绑定,其中$host-port为宿主主机的端口,而$container-port为容器的端口,如12345:80:
dockerrun-p$host-port:$container-portnginx
我们也可以只指定容器的端口号,此时Docker会自动分配一个主机上的端口号。
dockerrun-p$container-portnginx
对于Nginx,官方镜像在制作时指定暴露80和443端口用于http和https请求,对于这种在镜像中暴露的端口,可以在创建时使用以下方式全部指定:
dockerrun-Pnginx
此时,Docker会自动分配主机上的两个端口分别映射容器的80和443端口。自动分配的数量与镜像中暴露的端口数量对应。
查看端口
我们可以在dockerps-a中的PORTS栏看到端口映射情况。注意只有处于运行中的容器才会有实际的端口映射。
此外,我们还可以使用以下指令查看某一容器的端口映射:
dockerport$container-name
docker-compose
创建一个容器时,可能需要对多项参数进行限制,比如指定网络、指定数据卷、指定端口等等。而且,有时我们可能需要同时使用多个容器共同支撑应用,比如Nginx容器、php&php-fpm容器、MySQL容器、Redis容器等。
如果每次都使用各种参数,按某种顺序依次启动容器(容器之间可能存在先后顺序,比如要先启动PHP然后再启动Nginx容器)的话,会造成很多繁琐的操作。为了解决这个问题,我们可以使用docker-compose。
执行以下指令查看docker-compose可以执行的指令:
docker-compose--help
YAML
docker-compose依赖一个docker-compose.yml文件,用以指定容器数据卷、网络等。
.yml文件遵循YAML语法,这是一种使用缩进的语法。
样例
下面给出一个简单的样例,用以说明docker-compose的用法
version:'2.0' services: #启用一个镜像为nginx的容器并命名为web1 web1: image:nginx #开启80和443端口,实际映射端口由Docker指定 ports: -"80" -"443" #将该容器加入mynetwork中 networks: -"mynetwork" #指定该容器要在web2容器启动之后启动,且在其停止前停止 depends_on: -web2 web2: image:nginx ports: -"33333:80" networks: -"mynetwork" -"bridge" volumes: -"/mnt" networks: #创建一个驱动为bridge的网络,命名为mynetwork mynetwork: driver:bridge
其中,容器的实际名字为.yml文件所在目录名_.yml文件中指定的名字_序号,如mydir_web1_1。但是,在容器内部,可以使用mydir_web1_1也可以使用web1作为域名访问另一主机,这对于之后多容器共同支撑web服务是至关重要的。
更多的.yml文件的写法可以参考[YAML模板文件][7]
docker-compose的使用
生成容器
首先,我们需要有一个名为docker-compose.yml或docker-compose.yaml的文件,并进入该文件所在目录下,通过以下命令生成并启动:
docker-composeup
Docker会根据docker-compose.yml中的内容创建网络、数据卷和容器。
当然也可以加入参数-d使其生成后在后台运行:
docker-composeup-d
停止
停止容器可以使用:
docker-composestop
运行
再次运行容器可以使用
docker-composestart
查看日志
docker-composelogs
删除
通过以下命令可以删除容器,但不会删除之前创建的网络
docker-composerm
若想既删除容器,又删除网络,可以使用:
docker-composedown
注意,数据卷的删除仍要使用之前删除数据卷的方法。
生成&提交镜像
生成镜像
我们对使用某一镜像的容器做了修改,比如在使用centos这一镜像创建的容器中安装了nginx,此时我们可以将这一容器生成为一个新的镜像,这之后就可以通过这个新镜像创建其他容器,而这些容器也同样已经安装了nginx。
生成镜像可以使用如下方式:
dockercommit-m$commit-msg-a$author$container-id$namespace/$mirror-name:$tag
如:
dockercommit-m'installnginx'-a'dailybird'abcd1234dailybird/nginx:test
之后便可以通过dockerimages查看已经创建的镜像了。
提交镜像
我们可以将镜像提交到官方仓库中,这样就可以像最初获取镜像的方式一样获得自己制作的镜像了。
首先,我们需要在DockerHub上注册账户:https://hub.docker.com/
然后使用以下命令登录:
dockerlogin
之后会提示输入用户名和密码,显示登录成功后,用以下方式推送:
dockerpush$namespace/$mirror-name:$tag
由于国内访问DockerHub的速度较慢,我们也可以使用DaoCloud或阿里云的Docker服务,具体的推送方法可以访问之前给出的网址,参照其中的方法即可。
Dockerfile
使用已有容器创建镜像的方式固然可行,可当我们需要再次对镜像修改时,就需要再次生成容器、进行配置修改或软件安装、提交镜像。此外,不断在原有提交镜像的基础上修改提交会存在两个问题:
- 累积的修改条目不够直观,可能之后自己也不知道对原有镜像做了什么修改;
- 不断修改的过程在Docker看来是增量更新的过程。这一次的修改相当于在上一次的基础上增加了一个只读层用于记录本次的修改情况。而只读层的数量是有限的,也就意味着这种修改和提交的方式的操作次数是受限的。
那么,有没有一种更好的方式可以实现镜像的生成呢?类比docker-compose.yml,我们可以使用另一种类似配置文件的方式来指导镜像的生成,这就是Dockerfile。
Dockerfile可以指定新镜像的原镜像来源、对原镜像的操作、环境变量,以及以此创建容器时执行的指令等。
样例
#新镜像基于的原镜像 FROMcentos:centos6.8 #指明维护者 MAINTAINERdailybird#设置一些环境变量,使用\表示连接多个设置 ENVNGINX_VERSION1.11.11\ TEST_ENVhello #指定暴露的端口号, EXPOSE80443 #在原镜像基础上进行的修改 RUNyuminstall-ywgetiputils\ &&wgethttp://nginx.org/download/nginx-1.11.11.tar.gz #以此镜像创建并启动时,容器执行的指令,通常用于启动服务 CMD["echo","helloworld"]
比如使用以下配置可以在centos中安装nginx:
FROMcentos:centos6.8 MAINTAINERdailybirdEXPOSE80443 RUNcd/\ &&mkdirdata\ &&cddata\ &&mkdirnmp\ &&cdnmp\ &&yuminstall-ywgetpcre-develgccgcc-c++\ ncurses-develperlmakezlibzlib-devel\ opensslopenssl--develiputils\ &&wgethttp://nginx.org/download/nginx-1.11.11.tar.gz\ &&tarzxfnginx-1.11.11.tar.gz\ &&cdnginx-1.11.11\ &&./configure--prefix=/usr/local/nginx\ &&make&&makeinstall&&makeclean\
更多的Dockerfile指令可以参考Dockerfile指令。
Dockerfile的使用
使用Dockerfile创建镜像
首先,我们需要新建一个名为Dockerfile的文件(没有后缀),并写入一些配置内容。然后在该文件的目录中,通过以下指令创建镜像:
dockerbuild--tag$namespace/$mirror-name:$tag$dockerfile-dir
其中,$dockerfile-dir为Dockerfile所在目录,比如执行:
dockerbuild--tagdailybird/nginx-demo:demo./
等待一段时间之后,便可通过dockerimages看到新创建的镜像了。
docker-compose中使用Dockerfile
当我们需要启动一个新镜像时,可以先将此镜像创建出来,然后在docker-compose.yml文件中通过image指定新镜像;也可以直接通过以下方式将这两个步骤合并:
version:'2.0' services: web1: #build后的参数为Dockerfile文件所在的目录位置,替换原先的image build:./ ports: -"80" networks: -"mynetwork" #... #其他配置
此后,可以通过以下指令创建容器:
docker-composebuild docker-composeup
或者,直接执行:
docker-composeup--build
这时,Docker会自动创建一个镜像,并以此创建容器。
后记
关于Docker还有很多内容,比如备份、集群、插件等。不过这些就留到进一步研究之后再撰文吧。
问题备忘
权限问题
有时可能遇到如下Docker报错:
WARNING:Errorloadingconfigfile:/home/user/.docker/config.json-stat/home/user/.docker/config.json:permissiondenied
此时,可以通过以下方法解决:
sudochmod-Rg+rwx/your/path/to/.docker/
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。