我们都在说未来要“云”化,那么我们应该要将服务打包放到“云”上。那么我们的应用需要容器化,那么我们要安装Docker。
Docker是一个开源的PaaS产品,2013年开源发布Docker引擎后,迅速崛起。
本文介绍Docker的基本概念跟入门使用。
Docker容器是什么?
Docker跟虚拟机有些像,但Docker不是虚拟机。虚拟机是对硬件进行虚拟化,Docker则使用了操作系统级别的虚拟化技术。Docker容器运行在宿主机中,但容器之间是隔离的,并且将各自的依赖库、配置打包进了容器。
镜像(Image)
操作系统分为内核与用户空间。对于Linux而言,内核启动后会挂载文件系统。Docker镜像是一个特殊的文件系统,除了提供容器运行时需要的程序、库、资源和配置外,还包含了一些配置参数,以支持运行时的一些功能。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
容器(Container)
镜像(Image)和容器(Container)的关系,就像是类与实例一样:镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、暂停、停止、删除等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。因此容器可以拥有自己的 文件系统、网络配置、进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。
前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。
仓库(Repository)
镜像的分发到其他服务器上使用,需要一个分发中心服务。Docker Registry是这样的服务,而仓库则是镜像的仓储。一个Registry中可以包含多个仓库(Repository),每个仓库可以包含多个标签(Tag),每个标签对应一个镜像。
通常,一个仓库会包含同一软件的不同版本的镜像,我们可以通过 <用户名>/<仓库名>:<标签> 的格式来指定具体使用什么版本。latest是默认标签。比如nginx:latest。
Docker的基本命令
Docker运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker会从镜像仓库下载该镜像。
获取镜像
从公开的仓库(或私有仓库)可以获取镜像,如Docker Hub上:1
docker pull [选项] [Registry地址[:端口号]/]仓库名[:标签]
列举镜像
docker image ls1
2
3
4
5
6qilin:~ ryan$docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
gitlab/gitlab-ce latest e6b464b98aff 2 days ago 1.92GB
postgres latest f30ff596f17b 3 days ago 314MB
jenkins/jenkins lts 7e250da768ed 8 days ago 619MB
sonarqube latest e7cc715e8756 5 weeks ago 504MB
镜像包失去镜像名后(比如docker pull更新),旧的镜像没有名称了,称之为虚悬镜像(dangling)。
通过命令docker image ls -f dangling=true
可以查找到。
一般来说,虚悬镜像是可以随意删除的,可以用下面的命令删除:docker image prune
。
需要留意,可能有些依赖的镜像被下载下来,这些不是dangling。
删除镜像
1 | docker image rm [选项] <镜像1> [<镜像2> ...] |
运行容器
基于镜像新建一个容器并启动。下例中启动ubuntu中的bash并进行交互式操作。以Jenkins的操作指令示例:
1 | docker run -it -d -p port1:port2 jenkins/jenkins:lts |
docker run的参数:
-it:-i是交互式操作,-t终端。在交互式终端运行容器。
-d:守护式启动容器
-p port1:port2 表示宿主机和容器的端口映射
–name 表示给生成的容器起名字
-v /volume/in/host:/var/volume/in/container 数据卷挂载
对于已创建的处于stop状态的容器,可以使用docker start $containerId
再次启动容器。
查看容器
1 | docker ps -a |
查看容器的日志:1
2
3
4docker logs [-f] [t] [--tail] 容器名
-f --follows=true | false 是否跟踪输出,默认为 false
-t --timestamps=true | false 是否带时间戳,默认为 false
--tail="all" 显示最后多少条输出,默认为 all
docker -f $containerId
进入容器
如果要修改容器,可以用docker exec命令进入容器,
1 | docker exec -it $containerId bash |
用-it指定交互式终端进入,最后的bash是指定进入容器后执行的命令。
进入容器后可能会修改到配置,定制后需要将容器存储保存下来,就是在原有镜像的基础上,成为镜像。1
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
示例:1
2
3
4
5
6
7
8
9docker commit \
--author "Jason Chan <jasonchan@gmail.com>" \
--message "修改了默认网页" \
server \
nginx:v2
停止容器
1 | docker stop $containerId |
使用docker stop
来终止一个运行中的容器。
导出容器
1 | docker export 7691a814370e > container.tar |
可以将容器做一个快照,导出成为镜像。
以上是关于docker的container的一些入门介绍,进阶内容可以参考官网的介绍。
Docker Compose
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.
绝大多数情况下,我们的应用都是有外部依赖的,比如数据库,MQ或者外部服务。当我们把服务都容器化的时候,管理和协调这些容器跟应用本身,就变成一件糟心的事儿了。Docker的解决方案是Docker Compose。
Docker Compose允许我们通过一个配置文件定义整个应用,包括它的依赖。这样会使开发变得相对incredibly容易。使用Compose可以:
- 一行命令启动整个应用:
docker-compose up -d
- 简单的DNS解析:可以在
service-a
中直接使用http://service-b
调用service-b
- 一行配置挂载数据卷
下面是一个docker-compose.yml
文件的示例:
1 | version: '3' |
第一行version
定义了版本;services下配置了web
跟redis
两个服务(的容器)。ports定义了<HOST_PORT>:<CONTAINER_PORT>
的端口映射;volumes
定义了宿主机与容器文件系统的映射,例子中是将宿主机的当前目录挂载为容器内的/code
路径;environment
定义了环境变量。
实际上还可以配置网络,这一点没有谈到:容器间是隔离的,网络不是直接相通的。这是官网的一个示例图:
有兴趣可以从官网文档了解。
反向代理
为了让非宿主的机器能访问容器的服务,需要做反向代理。
创建一个包含web应用的容器,一般会做宿主机到容器的端口映射,如:
1 | docker run -p 8080:80 -d webapp |
使用了宿主机8080端口映射到容器的80端口。如果使用NGINX做反向代理,需要配置转发,参考配置如下:
1 | server { |
如果是uWSGI应用1
2
3
4
5
6
7
8
9
10
11
12
13server {
listen 80;
# server_name ; # 域名
# charset
charset utf-8;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8080;
uwsgi_read_timeout 120s;
}
}
还有什么想说的?
There is no problem in computer science that can’t be solved by adding another level of indirection.
嗯!
Author: Jason
Permalink: http://blog.knpc21.com/tech/docker-basic/
文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。
Comments