# Docker 基础
# 什么是docker?
Docker是基于go语言实现的开源容器项目,诞生于2013年年初,最初发起者是,dotCloud公司。
Docker 项目已加入Linux基金会,并遵循Apache2.0协议,全部代码再github上维护。
Docker的构想是要实现Build Ship and Run Any app anywhere
即通过对应用的封装,分发,布署,运行生命周期进行管理,达到应用组件一次封装,到处运行的目的。
这里的应用组件不局限于web应用,可以是一个编译环境,可以是一个数据库平台服务,甚至可以是操作系统和集群。
Docker的发展建立在Linux容器技术之上。
# 为什么使用Docker?
在云时代,应用程序可以脱离底层物理硬件的限制,在任何时间任何地点即可获取。这样子可以做到快速的分发和部署。通过Docker来打包应用,解耦应用和运行平台。降低开发成本和部署风险。
Docker优点
- 更快速的交付和部署
- 更高效的资源利用
- 更轻松的迁移和扩展
- 更简单地更新管理
# Docker核心概念
镜像: 只读模板,包含一个基本的操作系统 容器: 一个轻量级的沙箱,容器是从镜像创建的,应用的运行实例。可以启动开始停止删除,容器彼此间相互隔离。 仓库: 类似于代码仓库,是集中存放镜像文件的场所。
# Docker Image - Docker镜像
# 如何使用Docker镜像
Docker运行容器前需要本地存在对应的镜像,如果镜像没保存在本地,Docker会尝试先从默认镜像仓库下载。
使用docker pull
命令可以直接从Docker Hub镜像源来下载镜像。
docker pull NAME[:TAG]
NAME: 镜像的名称
TAG: 镜像的版本
eg: 综上,一个镜像需要的信息就是名称
+标签
docker pull ubuntu:14.04
14.04: Pulling from library/ubuntu
bae382666908: Pull complete
29ede3c02ff2: Pull complete
da4e69f33106: Pull complete
8d43e5f5d27f: Pull complete
b0de1abb17d6: Pull complete
Digest: sha256:6e3e3f3c5c36a91ba17ea002f63e5607ed6a8c8e5fbbddb31ad3e15638b51ebc
Status: Downloaded newer image for ubuntu:14.04
如果不显示的指定TAG
,默认会选择latest
标签。会下载最新版的镜像。
# 启动镜像
下载到本地后,可以利用该镜像创建一个容器
docker run -it ubuntu:14.04 bash
/*
-i
-t
*/
root@4a9c106836e1:/#
执行完成会进入bash界面,可以执行一些基本操作
# 查看镜像的信息
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
calculatorapp latest 1dec489fae9a 12 hours ago 955MB
<none> <none> 2dab0d648733 6 days ago 755MB
node 6.11.1 1ffbfd4a58ec 2 months ago 656MB
参数
docker iamges
-a 列出所以镜像
# 使用Tag命令添加镜像标签
docker tag ubuntu:lastest myubuntu:lastest
REPOSITORY TAG IMAGE ID CREATED SIZE
myubuntu lastest dea1945146b9 2 weeks ago 188MB
ubuntu 14.04 dea1945146b9 2 weeks ago 188MB
实际上看到IMAGE ID是一样的,所以上实际指向同一个镜像文件。
# 删除镜像
1.通过标签删除
docker rmi IMAGE[IMAGE...]
eg:
REPOSITORY TAG IMAGE ID CREATED SIZE
myubuntu lastest dea1945146b9 2 weeks ago 188MB
docker rmi myubuntu:latest
2.通过ID删除
docker rmi ID
REPOSITORY TAG IMAGE ID CREATED SIZE
myubuntu lastest dea1945146b9 2 weeks ago 188MB
docker rmi dea1945146b9
注意
在删除时,如果没有容器使用这个镜像,那么会直接删除该镜像及包含的所有层。
但是如果有容器使用了该镜像,会得到该提示
docker rmi myubuntu:lastest
Error response from daemon: conflict: unable to remove repository reference "myubuntu:lastest" (must force) - container 4a9c106836e1 is using its referenced image dea1945146b9
有两种方式可以解决:
- 使用
-f
参数强制删除(不推荐) - 先删除容器,在删除镜像
# 创建镜像
三种方式创建镜像:
- 基于已有镜像的容器创建
- 基于本地模板导入
- 基于Dockerfile创建
# Docker container - Docker 容器
容器是镜像的一个运行实例。
# 容器创建
使用docker create
创建完毕的容器处于停止状态,可以使用docker start命令来启动
docker create
-d 是否在后台运行
eg:
docker create -it ubuntu:latest
bb821ea158758312d0832d2c971aab1665cce73541f04f22ca292f979c871e2e
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bb821ea15875 ubuntu:latest "/bin/bash" 3seconds ago Created adoring_archimedes
# 启动容器
使用docker start
命令来启动一个已经创建的容器
docker start [container_name/container_id]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bb821ea15875 ubuntu:latest "/bin/bash" 3seconds ago Created adoring_archimedes
docker start bb821ea15875
or
docker start adoring_archimedes
# 查看运行的容器
使用docker ps
命令来查看正在运行的容器
docker ps
-a 查看所有的容器
# 新建并启动容器
docker run
= docker create
+ docker start
docker run
-i 让容器的标准输入保持打开
-t 让docker分配一个伪终端(pseudo-tty),并绑定到容器的标准输入上
eg:
docker run -it ubuntu:14.04 /bin/bash
在ubuntu14.04上启动一个bash终端,并允许用户交互
可以使用exit或者ctrl+d来退出容器
# 守护态运行(后台运行)
docker run -d ubuntu:14.04 /bin/bash
-d 后台运行并输出 container ID
注意
如果是以后台运行的,可以使用docker log [container_name/container_id]
的方式来获取容器的输出信息
# 终止容器
docker stop [container_name/container_id]
# 进入容器
在使用-d
参数时,容器启动会进入后台。用户无法看到容器中的信息,也无法进行操作
三种方式解决:
attach
命令(不推荐使用)exec
命令(推荐使用)- nsenter工具(不推荐)
docker exec -it [container_name/container_id] /bin/bash
-i 打开标准输入接受用户的输入
-t 让docker分配一个伪终端(pseudo-tty),并绑定到容器的标准输入上
-u 执行命令的用户
# 删除容器
docker rm [container_name/container_id]
-f 强制终止并删除一个正在运行的容器
# Docker Repository - Docker 仓库
仓库:
- 公有仓库
- 私有仓库
docker hub:docker官方的公共镜像仓库
# Docker 数据管理
容器管理数据有两种方式:
- 数据卷(Data Volumes): 容器内的数据直接映射到本地主机环境
- 数据卷容器(Data Volume Containers): 使用特定容器维护数据卷
# 数据卷
什么是数据卷? 可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器
优势:
# 如何创建数据卷?
三种方式:
- 容器内部创建一个数据卷
- 挂载一个主机目录作为数据卷
- 挂载一个本地的主机文件作为数据卷(不推荐)
# 容器内部创建一个数据卷
在容器内创建一个数据卷使用-v
参数,本质上就是容器内部创建了一个文件夹
docker run -it -v /webapp ubuntu
//在容器内部创建一个文件夹
-v Bind mount a volume
eg:
docker run -it ubuntu
root@f22d574bb63f:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
docker run -it -v /webapp ubuntu
root@c3acf065e9c2:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var webappz
//多了一个webapp文件夹
# 挂载一个主机目录作为数据卷(推荐)
也是使用-v
参数,
docker run -it -v /src/webapp:/opt/webapp ubuntu
//将本地的/src/webapp目录挂载到容器内部的/opt/webapp
本地目录路径必须是绝对路径
,如果目标目录不存在,docker会自动创建。但是如果目标存在,???
Docker 挂载的数据卷默认权限是读写(rw),也可以更改
# 数据卷容器
创建一个数据卷容器可以在多个容器之间共享一个持续更新的数据。
如何创建?
docker run -it --name dbdata -v /dbdata ubuntu
//创建一个dbdata的文件夹作为共享数据卷
--name 给容器起一个名字
其他容器如何使用这个共享的数据卷?
docker run -it --volumes-from dbdata --name db1 ubuntu
//将一个container名字为dbdata的数据卷也挂载到当前的容器中
--volumes-from Mount volumes from the specified container(s) 从指定的container来挂载卷
利用容器卷来做数据备份 1.备份
$ docker run --volumes-from dbdatasrc -v $(pws):/backup --name worker ubuntu tar cvf /back/backup.tar /dbdata
//将容器dbdatasrc内部的数据卷(/dbdata)挂载到新的ubuntu的容器上(起名为worker容器),此时worker容器内部会有/dbdata的数据卷.
//同时将/dbdata内部的所有数据压缩打包到worker容器下的/back目录下。 实现数据备份。
# 端口映射和容器互联
# 从外部访问容器应用(端口映射)
在启动容器的时候,如果不指定对应的参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。
如何让外部的访问容器?
1.通过-P
大写P
使用-P标记时,Docker会随机映射一个49000~49900的端口到容器开放的网络端口:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ad0d233c126 training/webapp "python app.py" 46 seconds ago Up 44 seconds 0.0.0.0:32768->5000/tcp dazzling_kirch
2.通过-p
小写p
可以指定要映射的端口
支持的格式
HostPort:Container | Ip:HostPort:Container | Ip::ContainerPort
第一种HostPort:Container
, 将本地的端口映射到容器的指定端口
映射所有接口地址
docker run --name test1 -p 5000:5000 training/webapp python app.py
//将本地的5000端口映射到容器的5000端口
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f7f8a05e63a9 training/webapp "python app.py" 3 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp ecstatic_einstein
docker run -p 5000:5000 -p 3000:80 ubuntu
这时绑定的是所有IP段的5000端口
到容器的5000
端口
第二种IP:HostPort:ContainerPort
, 将本地的指定IP的端口映射到容器的指定端口
映射到指定地址的指定端口
docker run --name test2 -p 127.0.0.1:5000:5000 training/webapp python app.py
//将本地的ip仅为127.0.0.1的5000映射到容器的5000
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bd4e352c3b48 training/webapp "python app.py" 2 minutes ago Up 2 minutes 127.0.0.1:5000->5000/tcp test1
第三种Ip::ContainerPort
,
映射到指定地址的任意端口
docker run --name test3 -p 127.0.0.1::5000 training/webapp python app.py
//绑定127.0.0.1的任意端口到容器的5000端口,本地主机会随机分配一个端口
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b804acc891df training/webapp "python app.py" 5 seconds ago Up 3 seconds 127.0.0.1:32768->5000/tcp test3
# 查看端口映射配置情况
docker port [container_name/container_id]
eg:
docker port b804acc891df
5000/tcp -> 127.0.0.1:32768
//表示容器的5000映射在本地主机的127.0.0.1:32768
or:
docker port b804acc891df 5000
127.0.0.1:32768
# 容器互连
容器互连是一种让多个容器中的应用进行快速交互的方式。它会在源和接收容器之间创建连接关系,接收容器可以通过容器名
快速的访问到源容器,而不用指定IP地址。
自定义容器命名,在创建容器的时候,使用--name
参数,否则系统会随机生成一个名字。
使用--link
参数可以让容器之间安全的进行交互。
eg:
1.创建一个新的数据库容器
$ docker run -d --name db-container training/postgres
2.创建一个新的web容器可以访问这个数据库容器
$ docker run -d -P --name web --link db-container:db training/webapp python app.py
// --link name:alias
//name: 要连接的容器名称
//alias: 连接的别名 (这个是啥意思?有什么用?)
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c5797ccc4f95 training/webapp "python app.py" 2 hours ago Up 2 hours 0.0.0.0:32769->5000/tcp web
cdd159304af3 training/postgres "su postgres -c '/..." 2 hours ago Up 2 hours 5432/tcp db-container
Docker 相当于在两个互连的容器之间创建了一个虚拟通道,而且不用映射他们的端口到宿主主机上。
docker通过两种方式为容器公开连接信息:
- 更新环境变量
- 更新/etc/hosts文件
我的理解:如果两个容器互连,那么他们之间肯定需要通过一些方式去联通。此处的db-container 相当于父容器。
它的hosts信息如下:
db-container
的/etc/hosts
:
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 cdd159304af3 <= 自己的容器的ID
那与之相连的web
容器就不太一样了
web
的/etc/hosts
:
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 db db-container cdd159304af3 <= --link 的参数db-container:db
172.17.0.3 c5797ccc4f95 <= 自己的容器的ID
# 参考资料
书籍:《Docker 技术入门与实战》
← 策略模式 Docker Compose →