常用命令直接跳至”Docker的常用命令”

查询常用命令直接跳至”Docker的常用命令”

配置阿里云镜像:

yum-config-manager –add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

前面章节为官方文档翻译 后面为常用操作和自启设置

Docker

是什么?

系统平滑移植,容器虚拟化技术

Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。

Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。

Docker 项目的目标是实现轻量级操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。

在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。

下面的图片比较了 Docker 和传统虚拟化方式的不同之处,可见容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。

传统虚拟化

Docker

应用场景

  • web应用的自动化打包和发布;
  • 自动化测试和持续集成、发布;
  • 在服务型环境中部署和调整数据库或其他的后台应用;
  • 从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境。

在任何地方开发、部署和运行任何应用

Docker是一款针对程序开发人员和系统管理员来开发、部署、运行应用的一款虚拟化平台。Docker 可以让你像使用集装箱一样快速的组合成应用,并且可以像运输标准集装箱一样,尽可能的屏蔽代码层面的差异。Docker 会尽可能的缩短从代码测试到产品部署的时间。

Docker 组件

  • The Docker Engine – Docker Engine 是一个基于虚拟化技术的轻量级并且功能强大的开源容器引擎管理工具。它可以将不同的 work flow 组合起来构建成你的应用。
  • Docker Hub 可以分享和管理你的images镜像的一个 Saas 服务。

为什么选择Docker

快速交付应用程序

  • 我们希望你的开发环境能够更好的提高你的工作效率。Docker容器能够帮助开发人员、系统管理员、QA和版本控制工程师在一个生产环节中一起协同工作。我们制定了一套容器标准,而这套容器标准能够使系统管理员更改容器的时候,程序员不需要关心容器的变化,而更专注自己的应用程序代码。从而隔离开了开发和管理,简化了开发和部署的成本。
  • 我们使应用的构建方式更加简单,可以快速的迭代你的应用,并且可以可视化的来查看应用的细微更改。这能够帮助组织里边的成员来更好的理解一个应用从构建到运行的过程。
  • Docker 是一个轻量级的容器,所以它的速度是非常快的,而容器的启动时间只需要一秒钟,从而大大的减少了开发、测试和部署的时间。轻松部署和扩展
  • Docker 容器可以运行在大多数的环境中,你可以在桌面环境、物理主机、虚拟主机再到数据中,私有或者公有云中部署。
  • 因为 Docker 可以从多平台下运行。你可以很容器的迁移你的应用程序。如果需要,你可以非常简单的将应用程序从测试环境迁移到云,或者从云迁移到测试环境。
  • Docker 是一个轻量级的容器,因此它可以在很短的时间内启动和关闭。当你需要的时候,你可以启动多个容器引擎,并且在不需要使用他们的时候,可以将他们全部关闭。

Docker的容器本身不需要额外创建虚拟机管理系统,因此你可以启动多套Docker容器,这样就可以充分发挥主机服务器的物理资源,也可以降低因为采购服务器licenses而带来的额外成本。

快速构建 轻松管理

因为Docker上述轻便,快速的特性。可以使您的应用达到快速迭代的目的。每次小的变更,马上就可以看到效果。而不用将若干个小变更积攒到一定程度再变更。每次变更一小部分其实是一种非常安全的方式。

Image镜像

介绍

基础镜像

在 Docker 的术语里,一个只读层被称为镜像,一个镜像是永久不会变的。

由于 Docker 使用一个统一文件系统,Docker 进程认为整个文件系统是以读写方式挂载的。 但是所有的变更都发生顶层的可写层,而下层的原始的只读镜像文件并未变化。由于镜像不 可写,所以镜像是无状态的。

镜像可写层

父镜像

镜像层次

每一个镜像都可能依赖于由一个或多个下层的组成的另一个镜像。我们有时说,下层那个 镜像是上层镜像的父镜像。

基础镜像

一个没有任何父镜像的镜像,谓之基础镜像。

镜像ID

所有镜像都是通过一个 64 位十六进制字符串 (内部是一个 256 bit 的值)来标识的。 为简化使用,前 12 个字符可以组成一个短ID,可以在命令行中使用。短ID还是有一定的 碰撞机率,所以服务器总是返回长ID。

获取镜像

1
docker pull

国内要配置镜像加速

列出本地镜像

1
docker images

在列出信息中,可以看到几个字段信息

  • 来自于哪个仓库,比如 ubuntu
  • TAG 信息,镜像的标记,比如 14.04,区分发行版本
  • 它的 ID 号(唯一)
  • 创建时间
  • 镜像大小

如果不指定具体的标记,则默认使用 latest 标记信息。

创建镜像

创建镜像有很多方法,用户可以从 Docker Hub 获取已有镜像并更新,也可以利用本地文件系统创建一个。

修改已有镜像

先使用下载的镜像启动容器。

1
2
$ sudo docker run -t -i training/sinatra /bin/bash
root@0b2616b0e5a8:/#

注意:记住容器的 ID,稍后还会用到。

在容器中添加 json 和 gem 两个应用。

1
root@0b2616b0e5a8:/# gem install json

当结束后,我们使用 exit 来退出,现在我们的容器已经被我们改变了,使用 docker commit 命令来提交更新后的副本。

1
2
$ sudo docker commit -m "Added json gem" -a "Docker Newbee" 0b2616b0e5a8 ouruser/sinatra:v2
4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c

其中,-m 来指定提交的说明信息,跟我们使用的版本控制工具一样;-a 可以指定更新的用户信息;之后是用来创建镜像的容器的 ID;最后指定目标镜像的仓库名和 tag 信息。创建成功后会返回这个镜像的 ID 信息。

使用 docker images 来查看新创建的镜像。

1
2
3
4
5
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
training/sinatra latest 5bc342fa0b91 10 hours ago 446.7 MB
ouruser/sinatra v2 3c59e02ddd1a 10 hours ago 446.7 MB
ouruser/sinatra latest 5db5f8471261 10 hours ago 446.7 MB

之后,可以使用新的镜像来启动容器

1
2
$ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash
root@78e82f680994:/#

利用 Dockerfile 来创建镜像

使用 docker commit 来扩展一个镜像比较简单,但是不方便在一个团队中分享。我们可以使用 docker build来创建一个新的镜像。为此,首先需要创建一个 Dockerfile,包含一些如何创建镜像的指令。

新建一个目录和一个 Dockerfile

1
2
3
$ mkdir sinatra
$ cd sinatra
$ touch Dockerfile

Dockerfile 中每一条指令都创建镜像的一层,例如:

1
2
3
4
5
6
# This is a comment
FROM ubuntu:14.04
MAINTAINER Docker Newbee <newbee@docker.com>
RUN apt-get -qq update
RUN apt-get -qqy install ruby ruby-dev
RUN gem install sinatra

Dockerfile 基本的语法是

  • 使用#来注释
  • FROM 指令告诉 Docker 使用哪个镜像作为基础
  • 接着是维护者的信息
  • RUN开头的指令会在创建中运行,比如安装一个软件包,在这里使用 apt-get 来安装了一些软件

编写完成 Dockerfile 后可以使用 docker build 来生成镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ sudo docker build -t="ouruser/sinatra:v2" .
Uploading context 2.56 kB
Uploading context
Step 0 : FROM ubuntu:14.04
---> 99ec81b80c55
Step 1 : MAINTAINER Newbee <newbee@docker.com>
---> Running in 7c5664a8a0c1
---> 2fa8ca4e2a13
Removing intermediate container 7c5664a8a0c1
Step 2 : RUN apt-get -qq update
---> Running in b07cc3fb4256
---> 50d21070ec0c
Removing intermediate container b07cc3fb4256
Step 3 : RUN apt-get -qqy install ruby ruby-dev
---> Running in a5b038dd127e
Selecting previously unselected package libasan0:amd64.
(Reading database ... 11518 files and directories currently installed.)
Preparing to unpack .../libasan0_4.8.2-19ubuntu1_amd64.deb ...
Setting up ruby (1:1.9.3.4) ...
Setting up ruby1.9.1 (1.9.3.484-2ubuntu1) ...
Processing triggers for libc-bin (2.19-0ubuntu6) ...
---> 2acb20f17878
Removing intermediate container a5b038dd127e
Step 4 : RUN gem install sinatra
---> Running in 5e9d0065c1f7
. . .
Successfully installed rack-protection-1.5.3
Successfully installed sinatra-1.4.5
4 gems installed
---> 324104cde6ad
Removing intermediate container 5e9d0065c1f7
Successfully built 324104cde6ad

其中 -t 标记来添加 tag,指定新的镜像的用户信息。 “.” 是 Dockerfile 所在的路径(当前目录),也可以替换为一个具体的 Dockerfile 的路径。

可以看到 build 进程在执行操作。它要做的第一件事情就是上传这个 Dockerfile 内容,因为所有的操作都要依据 Dockerfile 来进行。 然后,Dockfile 中的指令被一条一条的执行。每一步都创建了一个新的容器,在容器中执行指令并提交修改(就跟之前介绍过的 docker commit 一样)。当所有的指令都执行完毕之后,返回了最终的镜像 id。所有的中间步骤所产生的容器都被删除和清理了。

*注意一个镜像不能超过 127 层

此外,还可以利用 ADD 命令复制本地文件到镜像;用 EXPOSE 命令来向外部开放端口;用 CMD 命令来描述容器启动后运行的程序等。例如

1
2
3
4
5
6
# put my local web site in myApp folder to /var/www
ADD myApp /var/www
# expose httpd port
EXPOSE 80
# the command to run
CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"]

现在可以利用新创建的镜像来启动一个容器。

1
2
$ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash
root@8196968dac35:/#

还可以用 docker tag 命令来修改镜像的标签。

1
2
3
4
5
6
$ sudo docker tag 5db5f8471261 ouruser/sinatra:devel
$ sudo docker images ouruser/sinatra
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ouruser/sinatra latest 5db5f8471261 11 hours ago 446.7 MB
ouruser/sinatra devel 5db5f8471261 11 hours ago 446.7 MB
ouruser/sinatra v2 5db5f8471261 11 hours ago 446.7 MB

从本地文件系统导入

要从本地文件系统导入一个镜像,可以使用 openvz(容器虚拟化的先锋技术)的模板来创建: openvz 的模板下载地址为 templates 。

比如,先下载了一个 ubuntu-14.04 的镜像,之后使用以下命令导入:

1
sudo cat ubuntu-14.04-x86_64-minimal.tar.gz  |docker import - ubuntu:14.04

然后查看新导入的镜像。

1
2
3
docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 14.04 05ac7c0b9383 17 seconds ago 215.5 MB

上传镜像

用户可以通过 docker push 命令,把自己创建的镜像上传到仓库中来共享。例如,用户在 Docker Hub 上完成注册后,可以推送自己的镜像到仓库中。

1
2
3
4
$ sudo docker push ouruser/sinatra
The push refers to a repository [ouruser/sinatra] (len: 1)
Sending image list
Pushing repository ouruser/sinatra (3 tags)

存出和载入镜像

存出镜像

如果要导出镜像到本地文件,可以使用 docker save 命令。

1
2
3
4
5
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 14.04 c4ff7513909d 5 weeks ago 225.4 MB
...
$sudo docker save -o ubuntu_14.04.tar ubuntu:14.04

载入镜像

可以使用 docker load 从导出的本地文件中再导入到本地镜像库,例如

1
$ sudo docker load --input ubuntu_14.04.tar

1
$ sudo docker load < ubuntu_14.04.tar

这将导入镜像以及其相关的元数据信息(包括标签等)。

移除本地镜像

如果要移除本地的镜像,可以使用 docker rmi 命令。注意 docker rm 命令是移除容器。

1
2
3
4
5
$ sudo docker rmi training/sinatra
Untagged: training/sinatra:latest
Deleted: 5bc342fa0b91cabf65246837015197eecfa24b2213ed6a51a8974ae250fedd8d
Deleted: ed0fffdcdae5eb2c3a55549857a8be7fc8bc4241fb19ad714364cbfd7a56b22f
Deleted: 5c58979d73ae448df5af1d8142436d81116187a7633082650549c52c3a2418f0
  • 注意:在删除镜像之前要先用 docker rm 删掉依赖于这个镜像的所有容器。

镜像的实现原理

Docker 镜像是怎么实现增量的修改和维护的? 每个镜像都由很多层次构成,Docker 使用 Union FS 将这些不同的层结合到一个镜像中去。

通常 Union FS 有两个用途, 一方面可以实现不借助 LVM、RAID 将多个 disk 挂到同一个目录下,另一个更常用的就是将一个只读的分支和一个可写的分支联合在一起,Live CD 正是基于此方法可以允许在镜像不变的基础上允许用户在其上进行一些写操作。 Docker 在 AUFS 上构建的容器也是利用了类似的原理。

Docker容器

启动容器

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。

因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。

新建并启动

所需要的命令主要为 docker run

例如,下面的命令输出一个 “Hello World”,之后终止容器。

1
2
3
4
$ sudo docker run ubuntu:14.04 /bin/echo 'Hello world'
Hello world

docker run -d -p 80:80 docker/getting-started

这跟在本地直接执行 /bin/echo 'hello world' 几乎感觉不出任何区别。

下面的命令则启动一个 bash 终端,允许用户进行交互。

1
2
$ sudo docker run -t -i ubuntu:14.04 /bin/bash
root@af8bae53bdd3:/#

其中,-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。

在交互模式下,用户可以通过所创建的终端来输入命令,例如

1
2
3
4
root@af8bae53bdd3:/# pwd
/
root@af8bae53bdd3:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定的镜像,不存在就从公有仓库下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
  • 从地址池配置一个 ip 地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被终止

启动已终止容器

可以利用 docker start 命令,直接将一个已经终止的容器启动运行。

容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源。可以在伪终端中利用 pstop 来查看进程信息。

1
2
3
4
root@ba267838cc1b:/# ps
PID TTY TIME CMD
1 ? 00:00:00 bash
11 ? 00:00:00 ps

可见,容器中仅运行了指定的 bash 应用。这种特点使得 Docker 对资源的利用率极高,是货真价实的轻量级虚拟化。

守护态运行

更多的时候,需要让 Docker 容器在后台以守护态(Daemonized)形式运行。此时,可以通过添加 -d 参数来实现。

例如下面的命令会在后台运行容器。

1
2
$ sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147

容器启动后会返回一个唯一的 id,也可以通过 docker ps 命令来查看容器信息。

1
2
3
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e5535038e28 ubuntu:14.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute insane_babbage

要获取容器的输出信息,可以通过 docker logs 命令。

1
2
3
4
5
$ sudo docker logs insane_babbage
hello world
hello world
hello world
. . .

终止容器

可以使用 docker stop 来终止一个运行中的容器。

此外,当Docker容器中指定的应用终结时,容器也自动终止。 例如对于上一章节中只启动了一个终端的容器,用户通过 exit 命令或 Ctrl+d 来退出终端时,所创建的容器立刻终止。

终止状态的容器可以用 docker ps -a 命令看到。例如

1
2
3
4
sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ba267838cc1b ubuntu:14.04 "/bin/bash" 30 minutes ago Exited (0) About a minute ago trusting_newton
98e5efa7d997 training/webapp:latest "python app.py" About an hour ago Exited (0) 34 minutes ago backstabbing_pike

处于终止状态的容器,可以通过 docker start 命令来重新启动。

此外,docker restart 命令会将一个运行态的容器终止,然后再重新启动它。

进入容器

在使用 -d 参数时,容器启动后会进入后台。 某些时候需要进入容器进行操作,有很多种方法,包括使用docker attach 命令或 nsenter 工具等。

attach 命令

docker attach 是Docker自带的命令。下面示例如何使用该命令。

1
2
3
4
5
6
7
$ sudo docker run -idt ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia
$sudo docker attach nostalgic_hypatia
root@243c32535da7:/#

但是使用 attach 命令有时候并不方便。当多个窗口同时 attach 到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了。

nsenter 命令

安装

nsenter 工具在 util-linux 包2.23版本后包含。 如果系统中 util-linux 包没有该命令,可以按照下面的方法从源码安装。

1
2
3
$ cd /tmp; curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24;
$ ./configure --without-ncurses
$ make nsenter && sudo cp nsenter /usr/local/bin

使用

nsenter 可以访问另一个进程的名字空间。nsenter 要正常工作需要有 root 权限。 很不幸,Ubuntu 14.04 仍然使用的是 util-linux 2.20。安装最新版本的 util-linux(2.24)版,请按照以下步骤:

1
2
3
4
$ wget https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz; tar xzvf util-linux-2.24.tar.gz
$ cd util-linux-2.24
$ ./configure --without-ncurses && make nsenter
$ sudo cp nsenter /usr/local/bin

为了连接到容器,你还需要找到容器的第一个进程的 PID,可以通过下面的命令获取。

1
PID=$(docker inspect --format "{{ .State.Pid }}" <container>)

通过这个 PID,就可以连接到这个容器:

1
$ nsenter --target $PID --mount --uts --ipc --net --pid

下面给出一个完整的例子。

1
2
3
4
5
6
7
8
9
$ sudo docker run -idt ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia
$ PID=$(docker-pid 243c32535da7)
10981
$ sudo nsenter --target 10981 --mount --uts --ipc --net --pid
root@243c32535da7:/#

更简单的,建议大家下载 .bashrc_docker,并将内容放到 .bashrc 中。

1
2
$ wget -P ~ https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker;
$ echo "[ -f ~/.bashrc_docker ] && . ~/.bashrc_docker" >> ~/.bashrc; source ~/.bashrc

这个文件中定义了很多方便使用 Docker 的命令,例如 docker-pid 可以获取某个容器的 PID;而 docker-enter 可以进入容器或直接在容器内执行命令。

1
2
$ echo $(docker-pid <container>)
$ docker-enter <container> ls

导出和导入容器

导出容器

如果要导出本地某个容器,可以使用 docker export 命令。

1
2
3
4
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7691a814370e ubuntu:14.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test
$ sudo docker export 7691a814370e > ubuntu.tar

这样将导出容器快照到本地文件。

导入容器快照

可以使用 docker import 从容器快照文件中再导入为镜像,例如

1
2
3
4
$ cat ubuntu.tar | sudo docker import - test/ubuntu:v1.0
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB

此外,也可以通过指定 URL 或者某个目录来导入,例如

1
$sudo docker import http://example.com/exampleimage.tgz example/imagerepo

*注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

删除容器

可以使用 docker rm 来删除一个处于终止状态的容器。 例如

1
2
$sudo docker rm  trusting_newton
trusting_newton

如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。

数据卷

数据卷volumes

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:

  • 数据卷可以在容器之间共享和重用
  • 对数据卷的修改会立马生效
  • 对数据卷的更新,不会影响镜像
  • 卷会一直存在,直到没有容器使用

*数据卷的使用,类似于 Linux 下对目录或文件进行 mount。

创建一个数据卷

在用 docker run 命令的时候,使用 -v 标记来创建一个数据卷并挂载到容器里。在一次 run 中多次使用可以挂载多个数据卷。

下面创建一个 web 容器,并加载一个数据卷到容器的 /webapp 目录。

1
$ sudo docker run -d -P --name web -v /webapp training/webapp python app.py

*注意:也可以在 Dockerfile 中使用 VOLUME 来添加一个或者多个新的卷到由该镜像创建的任意容器。

挂载一个主机目录作为数据卷

使用 -v 标记也可以指定挂载一个本地主机的目录到容器中去。

1
$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py

上面的命令加载主机的 /src/webapp 目录到容器的 /opt/webapp 目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它。

*注意:Dockerfile 中不支持这种用法,这是因为 Dockerfile 是为了移植和分享用的。然而,不同操作系统的路径格式不一样,所以目前还不能支持。

Docker 挂载数据卷的默认权限是读写,用户也可以通过 :ro 指定为只读。

1
2
$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro
training/webapp python app.py

加了 :ro 之后,就挂载为只读了。

挂载一个本地主机文件作为数据卷

-v 标记也可以从主机挂载单个文件到容器中

1
$ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash

这样就可以记录在容器输入过的命令了。

*注意:如果直接挂载一个文件,很多文件编辑工具,包括 vi 或者 sed --in-place,可能会造成文件 inode 的改变,从 Docker 1.1 .0起,这会导致报错误信息。所以最简单的办法就直接挂载文件的父目录。

数据卷容器

如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。

数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。

首先,创建一个命名的数据卷容器 dbdata:

1
$ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres

然后,在其他容器中使用 --volumes-from 来挂载 dbdata 容器中的数据卷。

1
2
$ sudo docker run -d --volumes-from dbdata --name db1 training/postgres
$ sudo docker run -d --volumes-from dbdata --name db2 training/postgres

还可以使用多个 --volumes-from 参数来从多个容器挂载多个数据卷。 也可以从其他已经挂载了数据卷的容器来挂载数据卷。

1
$ sudo docker run -d --name db3 --volumes-from db1 training/postgres

*注意:使用 --volumes-from 参数所挂载数据卷的容器自己并不需要保持在运行状态。

如果删除了挂载的容器(包括 dbdata、db1 和 db2),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用 docker rm -v 命令来指定同时删除关联的容器。 这可以让用户在容器之间升级和移动数据卷。具体的操作将在下一节中进行讲解。

利用数据卷容器来备份、恢复、迁移数据卷

可以利用数据卷对其中的数据进行进行备份、恢复和迁移。

备份

首先使用 --volumes-from 标记来创建一个加载 dbdata 容器卷的容器,并从本地主机挂载当前到容器的 /backup 目录。命令如下:

1
$ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

容器启动后,使用了 tar 命令来将 dbdata 卷备份为本地的 /backup/backup.tar

恢复

如果要恢复数据到一个容器,首先创建一个带有数据卷的容器 dbdata2。

1
$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash

然后创建另一个容器,挂载 dbdata2 的容器,并使用 untar 解压备份文件到挂载的容器卷中。

1
2
$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf
/backup/backup.tar

安装docker

环境准备

  1. 需要一点点的liunx基础

  2. centos7

  3. 使用xshell连接远程服务器进行操作

  4. 卸载旧版本

yum remove docker

  1. 需要的安装包

yum install -y yum-utils

  1. 设置镜像的仓库

yum-config-manager –add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

更新索引

yum makecache fast

  1. 安装docker社区版

yum install docker-ce docker-ce-cli containerd.io

//其他方式

yum clean all yum makecache fastyum -y install docker-ce

  1. 启动docker

systemctl start docker

  1. 测试

docker version

docker run hello-world

  1. 查看镜像在不在

docker images

  1. 卸载docker

yum remove docker-ce docker-ce-cli containerd.io

yum rm -rf /var/lib/docker

阿里云镜像加速

登录阿里云 找到容器服务

找到镜像加速地址

配置使用

Docker的常用命令

帮助命令

1
2
3
docker version 		# 显示cker版本信息
docker info #显示docker 的系统信息 包括镜像和容器的数量
docker 命令 --help #帮助命令

镜像命令

docker images

1
2
3
4
5
6
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 5 months ago 13.3kB
# 可选
-a --all #列出所有镜像的详细信息
-q --quiet #列出镜像的id

docker search 搜索镜像

1
2
#可选项目
-f --filter=STARS=3000 #搜索出镜像大于3000的

docker pull 下载镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@localhost ~]# docker pull mysql

Using default tag: latest #如果不写 默认 latest
latest: Pulling from library/mysql
8559a31e96f4: Pull complete # 分层下载 docker images的核心 联合文件系统
d51ce1c2e575: Pull complete
c2344adc4858: Pull complete
fcf3ceff18fc: Pull complete
16da0c38dc5b: Pull complete
b905d1797e97: Pull complete
4b50d1c6b05c: Pull complete
c75914a65ca2: Pull complete
1ae8042bdd09: Downloading [=> ] 3.734MB/111.5MB
453ac13c00a3: Download complete
9e680cd72f08: Download complete
a6b5dc864b6c: Download complete
Digest: sha256:8b7b328a7ff6de46ef96bcf83af048cb00a1c86282bfca0cb119c84568b4caf6
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest

docker rmi 删除镜像 $(docker images -aq) 全部删除

1
2
docker rmi  -f 镜像 ID #删除指定内容
docker rmi -f 镜像 ID $(docker images -aq) 全部删除

容器命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
docker run [可选参数] image

#参数说明
--name ="Name" 容器名字 tomcat 01 用来区分容器

-d 后台运行
-it 使用交互方式 运行 进入容器 查看内容
-p 指定容器的端口 -p 8080:8080
-P 随机指定端口
-p 主机端口:容器端口
-p 容器端口

# 测试 启动并进入 centos 基础版本
[root@localhost ~]# docker run -it centos /bin/bash
[root@fd52fe0bc9f8 /]#

# 退回到主机
exit

docker ps 当前正在运行的容器
docker ps -a 曾经运行过的
-n= ? 显示最近创建的容器
-q 只显示容器的编号
-aq 显示所有容器 的编号


# ctrl+p+q 容器不停止 退出
删除容器
docker rm 容器id 不能删除正在运行的容器
docker rm -f $(docker ps -aq) 删除所有容器
docker ps -a -q|xargs docker rm

启动和停止 容器的操作

1
2
3
4
docker start 容器id
docker restart 容器id
docker stop 容器id
docker kill 容器id # 强制停止

常用其他命令

后台启动

1
2
3
# 命令docker run -d 镜像名
docker run -d centos
常见的坑 docker 容器使用后台运行 就必须要有一个前台进程

查看日志命令

1
docker logs  -tf --tail number 容器

查看容器中的进程信息

1
docker top 容器id

查看镜像的元数据

1
docker inspect 容器id

进入当前正在运行的容器

1
2
3
4
5
通常容器都是使用后台 
#方式一
docker exec -it 容器id bashShell
#方式二
docker attach 容器ID

方式一 进入之后开启一个新的终端
方式二 进入容器正在执行的终端

从容器内拷贝文件到主机上

1
2
3
4
5
6
7
8
9
docker cp 容器id:容器内路径 目的主机路径
attach 进入 容器

#touch test.java 新建文件
docker cp id:/home/test.java /home 拷贝

未来使用-v卷的技术 可以实现自动
[root@localhost ~]# curl localhost:8888
端口 暴露

以后要部署项目 如果每次进入容器 十分麻烦 webapps 在外部放置项目 就自动同步到内部

1
2
3
4
5
6
7
8
#es 暴露的端口很多
#es 十分耗内存
#es 的数据一般需要放置到安全目录

docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag


--net网络配置

docker stats 查看cpu的状态

1
2
增加内存限制 修改配置参数 -e 环境配置参数
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.7.1

相关自启设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# linux自动启动docker
systemctl enable docker.service

# docker容器自动启动设置 查看id
docker ps -a
docker restart <imageid>

docker run --restart=always
# 创建时:总是auto restart容器。
docker run -d --restart=always xxx
#  10次重启
docker run -d --restart=on-failure:10 xxx
# 如果已经启动了则可以使用如下命令:
docker update --restart=always <CONTAINER ID>

Manjaro基于archlinux的系统 自用备份 可无视

Manjaro安装Docker(自用备份)

基本安装#

1
2
3
4
5
6
7
8
9
10
Copy# Pacman 安装 Docker
sudo pacman -S docker
# 启动docker服务
sudo systemctl start docker

# 查看docker服务的状态
sudo systemctl status docker

# 设置docker开机启动服务
sudo systemctl enable docker

干掉讨厌的 sudo#

1
2
3
4
5
6
7
8
9
10
11
Copy# 如果还没有 docker group 就添加一个
sudo groupadd docker
# 将自己的登录名(${USER} )加入该 group 内。然后退出并重新登录就生效啦
sudo gpasswd -a ${USER} docker
# 重启 docker 服务
sudo systemctl restart docker
# 切换当前会话到新 group 或者重启 X 会话
# 注意,这一步是必须的,否则因为 groups 命令获取到的是缓存的组信息,刚添加的组信息未能生效,所以 docker images 执行时同样有错。
newgrp - docker
OR
pkill X

Docker 安装mqsql

1
2
docker run --privileged=true
-p 3306:3306 --name mysql -v //Users/xieyingtao/文档/项目/xytmall-docker/mysql/log:/var/log/mysql -v /Users/xieyingtao/文档/项目/xytmall-docker/mysql/data:/var/lib/mysql -v /Users/xieyingtao/文档/项目/xytmall-docker/mysql/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql
  • -p: 将容器的3306的端口映射到主机的3306
  • -v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 
//根目录选择自身实际最大磁盘路径 一般为/home 或者定义/data
vi /data/mysql/conf/my.cnf

//insert 插入以下内容

[mysqld]

#服务端口号 默认3306
port=3306
user=mysql
#mysql数据文件所在位置
datadir=/var/lib/mysql

#pid
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
default-time-zone = '+8:00'

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
# 允许访问的IP网段
bind-address=0.0.0.0

#只能用IP地址检查客户端的登录,不用主机名
skip_name_resolve=1

#事务隔离级别,默认为可重复读,mysql默认可重复读级别(此级别下可能参数很多间隙锁,影响性能)
transaction_isolation=READ-COMMITTED


#是否对sql语句大小写敏感,1表示不敏感
lower_case_table_names=1

#最大连接数
max_connections=400

#最大错误连接数
max_connect_errors=1000

#TIMESTAMP如果没有显示声明NOT NULL,允许NULL值
explicit_defaults_for_timestamp=true

#SQL数据包发送的大小,如果有BLOB对象建议修改成1G
max_allowed_packet=1G

#数据库错误日志文件
log-error=/var/log/mysqld.log
1
docker run --privileged=true -p 3306:3306 -m 1g --name mysql -v /data/mysql/conf:/etc/mysql/conf.d -v /data/mysql/logs:/var/log/mysql -v /data/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root123 -d mysql:8.0.30

开启远程连接权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
使用Docker命令进去mysql中

docker exec -it 容器名 /bin/bash
登录mysql数据库

mysql -u root -p
远程连接授权

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;


# 进入mysql容器
docker exec -it mysql bash
# -u后接账户 -p接密码
mysql -uroot -p123456
# 外网范围授权
grant all privileges on *.* to root@'%' identified by "password";
# 刷新权限
flush privileges;
# 一定要更新密码,否则Navicat连接报1045错误
alter user 'root'@'%' identified with mysql_native_password by '123456';
# 刷新权限


grant all privileges on *.* to 'root'@'%'

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root'


资料参考: http://www.dockerinfo.net/document ;狂神说java