什么是Docker
- Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。
- Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
- Docker又称为负载均衡入口
Docker好处
1. 真正实现一次编译到处运行
2. 更高效的利用系统资源
3. 更快速的启动时间
4. 一致的运行环境
5. 持续交付和部署
6. 更轻松的迁移
7. 更轻松的维护和扩展
对比传统虚拟机总结
特性 | 容器 | 虚拟机 |
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB | 一般为 GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
Docker 引擎是一个包含以下主要组件的客户端服务器应用程序。
- 一种服务器,它是一种称为守护进程并且长时间运行的程序。
- REST API用于指定程序可以用来与守护进程通信的接口,并指示它做什么。
- 一个有命令行界面 (CLI) 工具的客户端。
Docker 引擎组件的流程如下图所示:
Docker 系统架构
概述
Docker 使用客户端-服务器 (C/S) 架构模式,使用远程 API 来管理和创建 Docker 容器。
Docker 容器通过 Docker 镜像来创建。
容器与镜像的关系类似于面向对象编程中的对象与类。
Docker | 面向对象 |
容器 | 对象 |
镜像 | 类 |
标题 | 说明 |
镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板。 |
容器(Container) | 容器是独立运行的一个或一组应用。 |
客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker API (https://docs.docker.com/reference/api/docker_remote_api) 与 Docker 的守护进程通信。 |
主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
仓库(Registry) | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。 |
Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
Docker 常用命令
查看 Docker 版本
docker version
从 Docker 文件构建 Docker 映像
docker build -t image-name docker-file-location
运行 Docker 映像
docker run -d image-name
查看可用的 Docker 映像
docker images
查看最近的运行容器
docker ps -l
查看所有正在运行的容器
docker ps -a
停止运行容器
docker stop container_id
删除一个镜像
docker rmi image-name
删除所有镜像
docker rmi $(docker images -q)
强制删除所有镜像
docker rmi -r $(docker images -q)
删除所有虚悬镜像
docker rmi $(docker images -q -f dangling=true)
删除所有容器
docker rm $(docker ps -a -q)
进入 Docker 容器
docker exec -it container-id /bin/bash
查看所有数据卷
docker volume ls
删除指定数据卷
docker volume rm [volume_name]
删除所有未关联的数据卷
docker volume rm $(docker volume ls -qf dangling=true)
从主机复制文件到容器
sudo docker cp host_path containerID:container_path
从容器复制文件到主机
sudo docker cp containerID:container_path host_path
Ubuntu 安装Docker
- 操作系统必须是X64 Docker必须是带(LTS)的版本
使用脚本自动安装
- 修改Docker数据源
- 更新数据源
- 安装docker
- 先升级数据源
sudo apt-get update
curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun
Docker 镜像加速器
- 进入/etc/docker
- 在daemon.json 中写入如下内容 (如果文件不存在请新建该文件)
{
"registry-mirrors": ["https://4670ldli.mirror.aliyuncs.com"]
}
3.之后重新启动服务。
systemctl restart docker
下载tomcat
docker pull tomcat
docker pull tomcat:跟要下载的版本号
启动tomcat
docker run -p 8080:8080 tomcat
关闭tomcat
ctrl+c
docker的三大组件:镜像,容器,仓库
从 Docker 镜像仓库获取镜像的命令是docker pull
。其命令格式为
docker pull[选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
docker pull tomcat:jre-9
- Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。
- 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
下载ubuntu 16.04版本
docker pull ubuntu:16.04
运行
有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 ubuntu:16.04 为例,如果我们打算启动里面的 bash 并且进行交互式操作的话,可以执行下面的命令。
docker run -it --rm ubuntu:16.04 bash
-
-it
:这是两个参数,一个是-i
:交互式操作,一个是-t
终端。我们这里打算进入bash
执行一些命令并查看返回结果,因此我们需要交互式终端。 -
--rm
:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动docker rm
。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。 -
ubuntu:16.04
:这是指用ubuntu:16.04
镜像为基础来启动容器。 -
bash
:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是bash
。
进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了cat /etc/os-release
,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是Ubuntu 16.04.4 LTS
系统。
最后我们通过 exit或者ctrl+d
退出了这个容器。
docker run -it --rm ubuntu:16.04 bash
-i交互式操作
-t 终端
--rm容器退出后随之将其删除
ubuntu:16.04是指以这个为镜像
bash有个交互式 Shell,因此用bash
查看系统信息
cat /etc/os-release
查看Docker容器
docker ps 只查看运行的容器
docker ps -a 查看所有容器
docker rm ****删除容器ID
列出镜像
可以使用docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 16.04 5f2bf26e3524 13 days ago 123MB
tomcat latest 882487b8be1d 3 weeks ago 507MB
列表包含了仓库名
、标签
、镜像``````ID
、创建时间
以及 所占用的空间
。
列出镜像体积
使用命令docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 0 629.4MB 629.4MB (100%)
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
删除虚玄镜像
docker image prune
docker rmi -f IMAGE ID
- 另外一个需要注意的问题是,
docker image ls
列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用
,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。
中间层镜像
为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像。所以在使用一段时间后,可能会看到一些依赖的中间层镜像。默认的 docker image ls
列表中只会显示顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加-a
参数。
docker image ls -a
列出部分镜像
docker image ubuntu 列出所有名称中包含ubuntu的
docker image ubuntu:16.04 列出所有名称中包含ubuntu:16.04的
只列出镜像的名称ID
docker image ls -q
只列出镜像的名称ID和镜像的名称
docker image ls --format "{{.ID}}: {{.Repository}}"
删除本地镜像
使用docker image rm
命令删除本地镜像
首先docker rmi时指定名称,而非image id
docker rmi -f 名称
docker image rm [选项] <镜像1> [<镜像2> ...]
镜像的定制
- 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
- Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
docker里面查看目录ls -al
进入docker内部的tomcat
docker exec -it 名称ID bash
Dockerfile 定制镜像
在一个usr/local
里面简历建立一个空白目录以```tomcat``为例
cd /usr/local
mkdir tomcat
cd tomcat
在tomcat里面建一个为Dockerfile的文件vi Dockerfile
以tomcat为例其内容为
FROM tomcat
FROM
基础镜像是必须指定的。而FROM
就是指定基础镜像,因此一个Dockerfile
中 FROM
是必备的指令,并且必须是第一条指令。
RUN
RUN
指令是用来执行命令行命令的。由于命令行的强大能力,RUN
指令在定制镜像时是最常用的指令之一。其格式有两种:
- shell 格式
RUN <命令>
,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式
RUN echo '<h1>Hello, Docker!</h1>' > /usr/local/tomcat/webapps/ROOT/index.html
Docker里面tomcat ROOT的路径
- exec 格式
RUN ["可执行文件", "参数1", "参数2"]
,这更像是函数调用中的格式。
构建镜像
在Dockerfile
文件所在目录执行
docker build -t 自己起的镜像名称 . "."表示当前目录
以交互的形式进入
docker run -it 镜像名称 bash
在镜像内部查看目录用的是ls -al
而不是ll
- 想要删容器需要先删除镜像删除时容器不能运行
- 删除容器之后删除徐铉镜像
docker image prune
在Dockerfile
文件所在目录执行:
$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM nginx
---> e43d811ce2f4
Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
---> Running in 9cdc27646c7b
---> 44aa4490ce2c
Removing intermediate container 9cdc27646c7b
Successfully built 44aa4490ce2c
操作docker容器
启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。
新建并启动
所需要的命令主要为docker run
。
docker run ubuntu:14.04 /bin/echo 'Hello world'
这跟在本地直接执行/bin/echo 'hello world'
几乎感觉不出任何区别。
启动一个 bash 终端,允许用户进行交互。
docker run -t -i ubuntu:14.04 /bin/bash
root@ed6c059d9964:/#
-t
选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上,-i
则让容器的标准输入保持打开。
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
启动已终止容器
可以利用docker container start
命令,直接将一个已经终止的容器启动运行。
可以在伪终端中利用ps
或top
来查看进程信息。
守护态运行
更多的时候,需要让Docker
在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加-d
参数来实现。
如果不使用-d
参数运行容器。
$ docker run ubuntu:17.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
hello world
hello world
hello world
hello world
容器会把输出的结果 (STDOUT) 打印到宿主机上面
如果使用-d
参数运行容器。
$ docker run -d ubuntu:16.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a
此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面(输出结果可以用docker logs
查看)。
注: 容器是否会长久运行,是和docker run
指定的命令有关,和-d
参数无关。
使用-d
参数启动后会返回一个唯一的id
,也可以通过docker container ls
命令来查看容器信息。
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77b2dc01fe0f ubuntu:16.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright
要获取容器的输出信息,可以通过 docker container logs 命令。
$ docker container logs [container ID or NAMES]
hello world
hello world
hello world
docker ps -a
等同于 docker container ls -a
启动暂停的docker 容器docker restart 容器ID
停止docker容器docker stop 容器名称
自定义一个容器为tomcatdocker run -p 8080:8080 --name tomcat tomcat
启动一个tomcat镜像端口为8080
在后台运行一个端口号为8081的tomcat2
docker run -p 8081:8080 --name tomcat2 -d tomcat
所有未运行容器全部删除
docker container prune
可以使用docker container stop 容器名称
来终止一个运行中的容器。
终止状态的容器可以用docker container ls -a
命令看到
处于终止状态的容器,可以通过docker container start 容器名称
命令来重新启动。
docker container restart 容器名称
命令会将一个运行态的容器终止,然后再重新启动它。
进入容器
某些时候需要进入容器进行操作,包括使用docker attach
命令或docker exec
命令
attach 命令
docker attach
是 Docker 自带的命令。下面示例如何使用该命令。
$ docker run -dit ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia
$ docker attach 243c
root@243c32535da7:/#
注意: 如果从这个 stdin 中 exit,会导致容器的停止。
exec 命令
docker exec
后边可以跟多个参数,这里主要说明 -i``````-t
参数。
只用-i
参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。
当-i``````-t
参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
$ docker run -dit ubuntu
69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69d137adef7a ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds zealous_swirles
$ docker exec -i 69d1 bash
ls
bin
boot
dev
...
$ docker exec -it 69d1 bash
root@69d137adef7a:/#
如果从这个 stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 docker exec
的原因。
更多参数说明请使用 docker exec --help
查看。
Docker Hub
通过执行docker login
命令登录 Docker Hub。通过docker logout
退出登录.
通过docker search 镜像名称(例如tomcat)
命令来查找官方仓库中的镜像,并利用 docker pull
命令来将它下载到本地。
推送镜像
登录后通过docker push
命令来将自己的镜像推送到Docker Hub
。
以下命令中的username
请替换为你的 Docker 账号用户名。
$ docker tag ubuntu:17.10 username/ubuntu:17.10
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 17.10 275d79972a86 6 days ago 94.6MB
username/ubuntu 17.10 275d79972a86 6 days ago 94.6MB
$ docker push username/ubuntu:17.10
$ docker search username
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
username/ubuntu
Docker 私有仓库
安装运行 docker-registry
容器运行
你可以通过获取官方registry
镜像来运行。
$ docker run -d -p 5000:5000 --restart=always --name registry registry
在私有仓库上传、搜索、下载镜像
创建好私有仓库之后,就可以使用docker tag
来标记一个镜像,然后推送它到仓库例如私有仓库地址为127.0.0.1:5000
。
先在本机查看已有的镜像。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 16.04 5f2bf26e3524 4 weeks ago 123MB
使用docker tag
将ubuntu:latest
这个镜像标记为 127.0.0.1:5000/ubuntu:latest。
格式为docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
。
$ docker tag ubuntu:16.04 172.0.0.1:5000/ubuntu:16.04
REPOSITORY TAG IMAGE ID CREATED SIZE
127.0.0.1:5000/ubuntu 16.04 5f2bf26e3524 4 weeks ago 123MB
使用docker push
上传标记的镜像。
$ docker push 127.0.0.1:5000/ubuntu
The push refers to repository [127.0.0.1:5000/ubuntu]
aa7f8c8d5f39: Pushed
48817fbd6c92: Pushed
1b039d138968: Pushed
7082d7d696f8: Pushed
16.04: digest: sha256:b1c268ca7c73556456ffc3318eb2a8e7ac6ad257ef5788d50dc1db4a3e3bd2ac size: 1150
用curl
查看仓库中的镜像。
$ curl 127.0.0.1:5000/v2/_catalog
{"repositories":["ubuntu"]}
数据卷
数据卷也可以称之为Docker容器的持久化
-
数据卷
可以在容器之间共享和重用 - 对
数据卷
的修改会立马生效 - 对
数据卷
的更新,不会影响镜像 -
数据卷
默认会一直存在,即使容器被删除
运行容器:Docker 构建Tomcat
docker run --name tomcat -p 8080:8080 -v $PWD/test:/usr/local/tomcat/webapps/test -d tomcat
命令说明:
- -p 8080:8080:将容器的8080端口映射到主机的8080端口
- -v $PWD/test:/usr/local/tomcat/webapps/test:将主机中当前目录下的test挂载到容器的/test
查看容器启动情况
root@Ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a99367be6697 tomcat "catalina.sh run" 2 minutes ago Up 2 minutes 0.0.0.0:8081->8080/tcp tomcat1
Docker 构建MySQL
查找Docker Hub
上的MySQL
镜像docker search mysql
拉取官方的镜像docker pull mysql
运行容器:
docker run -p 3306:3306 --name mysql \
-v /usr/local/docker/mysql/conf:/etc/mysql \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.7.22
命令参数:
-
-p 3306:3306
:将容器的3306端口映射到主机的3306端口 -
-v /usr/local/docker/mysql/conf:/etc/mysql
:将主机当前目录下的 conf 挂载到容器的 /etc/mysql -
-v /usr/local/docker/mysql/logs:/var/log/mysql
:将主机当前目录下的 logs 目录挂载到容器的 /var/log/mysql -
-v /usr/local/docker/mysql/data:/var/lib/mysql
:将主机当前目录下的 data 目录挂载到容器的 /var/lib/mysql -
-e MYSQL\_ROOT\_PASSWORD=123456
:初始化root用户的密码