Docker学习记录

Posted by Shenpotato on April 2, 2020

学习主要基于RUNOOB的教程进行学习记录

docker源码地址:https://github.com/docker/docker-ce

一、Docker 简介

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

1. 应用场景

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

2. 架构

  • 镜像(Image):Docker的镜像,相当于是一个root文件系统
  • 容器(Container):镜像类似于面向对象程序设计中的类,容器即为实体。镜像是静态的定义,容器事镜像运行时的实体。容器可以被创建,启动,停止,删除和暂停
  • 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像

Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。

概念 说明
Docker 镜像(Images) Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。
Docker 容器(Container) 容器是独立运行的一个或一组应用,是镜像运行时的实体。
Docker 客户端(Client) Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。
Docker 主机(Host) 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
Docker Registry Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 **<仓库名>:<标签>** 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 **latest** 作为默认标签。
Docker Machine Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。

二、安装

1. Mac 安装

1
brew cask install docker

或者下载docker安装包

1
docker --version 					#查看docker当前版本

2. 镜像加速

使用网易的镜像加速

1
http://hub-mirror.c.163.com

在任务栏点击 Docker for mac 应用图标 -> Perferences… -> Daemon -> Registry mirrors。在列表中填写加速器地址即可。修改完成之后,点击 Apply & Restart 按钮,Docker 就会重启并应用配置的镜像地址了。

三、容器使用

1. hello world

1
docker run ubuntu:15.10 /bin/echo "Hello World"
  • docker: Docker的二进制执行文件

  • run:与docker组合,表示运行一个容器
  • ubuntu:15.10:执行要运行的镜像,docker先在本地主机上查找镜像是否存在,若不存在,docker从镜像仓库Docker Hub下载公共镜像
  • /bin/echo “Hello World”:在启动的容器中执行的命令

2. 交互式容器

1
docker run -i -t ubuntu:15.10 /bin/bash
  • t:在新容器中制定一个终端
  • i:允许你对容器内的标准输入进行交互

运行后,我们即进入到一个ubuntu的容器系统中,使用exit / ctrl + D退出当前容器,回到主机

3. 后台方式启动容器

1
2
docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63
  • d:后台方式打开容器
  • 返回的长串字符是容器ID
1
2
3
docker ps 				# 查看当前容器状态
docker logs container id / container name 			#查看容器内的标准输出
docker stop container id / container name 		  #停止容器

4. 容器基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
docker pull ubuntu			# 载入ubuntu镜像

docker run -it ubuntu /bin/bash			# 以命令行模式进入容器,/bin/bash实现交互式shell

docker stop/restart			# 停止/重启容器

docker run -itd --name ubuntu-test ubuntu /bin/bash			#后台方式打开容器
docker attach containerid			#打开的容器,退出时容器停止运行
docker exec -it containerid 				#打开的容器,退出时容器不停止运行

docker export container id > name.tar 		#导出本地容器
cat docker/name.tar | docker import - test/ubuntu:v1		#从容器快照文件中再导入为镜像
docker import http://example.com/exampleimage.tgz example/imagerepo  #制定url导入镜像

docker rm -f container id				#删除容器

5. 运行Web应用

1
2
docker pull training/webapp		#载入镜像
docker run -d -P serveraddress:portid:portid training/webapp python app. py
  • -P:将容器内部使用的网络端口映射到我们使用的主机上。

通过192.168.239.130:portid,访问Web应用

1
2
3
4
5
6
7
docker port container id / container name 			#查看指定容器的端口映射

docker logs -f container id 			# 容器内的标准输出

docker top container 				#容器内部运行的进程

docker insepect 						#查看docker的底层信息,返回一个json文件记录docker的配置和状态信息

四、镜像使用

1
docker images 			#列出本地主机上的镜像
  • REPOSITORY:表示镜像的仓库源
  • TAG:镜像的标签,表示版本
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小
1
2
3
docker search name 			#搜索镜像,也可以使用Docker Hub

docker rmi imagename		#删除镜像

1. 更新已有镜像

1
2
3
4
5
apt-get update 			#在运行的容器中执行,更新镜像

exit								#退出		

docker commit -m="" -a="" containerid targetImgaename  #用某一个容器创建镜像,m为提交信息,a为作者

2. 构建镜像

使用docker build创建一个新的镜像。需要创建一个Dockerfile文件,包含指令来告诉Docker如何构建镜像

1
2
3
4
5
6
7
8
9
10
11
runoob@runoob:~$ cat Dockerfile 
FROM    centos:6.7
MAINTAINER      Fisher "fisher@sudops.com"

RUN     /bin/echo 'root:123456' |chpasswd
RUN     useradd runoob
RUN     /bin/echo 'runoob:123456' |chpasswd
RUN     /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local
EXPOSE  22
EXPOSE  80
CMD     /usr/sbin/sshd -D

每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。

第一条FROM,指定使用哪个镜像源

RUN 指令告诉docker 在镜像内执行命令,安装了什么。。。

然后,我们使用 Dockerfile 文件,通过 docker build 命令来构建一个镜像。

1
docker build -t runoob/centos:6.7 .
  • -t :指定要创建的目标镜像名
  • . :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径

使用docker tag命令,为镜像增加一个新的标签

1
docker tag 860c279d2fec runoob/centos:dev

五、Dockerfile

Dockerfile是一个用来构建镜像的文本文件,包含了构建镜像所需的指令和说明

1. dockerfile文件介绍

1
2
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
  • From:定制的镜像都是基于From的镜像,此处以nginx作为基础镜像,后续操作都是基于nginx
  • Run:用于执行后面跟着的命令行命令,可以使用shell格式/exec格式
1
2
3
4
5
6
7
8
shell 格式
Run <命令行命令>

exec 格式
RUN ["可执行文件", "参数1", "参数2"]

RUN ["./test.php", "dev", "offline"]
RUN ./test.php dev offline

注意:Dockerfile的指令每执行一次都会在docker上新建一层,因此要避免过多无意义的层

1
2
3
4
FROM centos
RUN yum install wget \
		&& wget -0 redis.tar.gz "https://download.redis.io/releases/redis-5.0.3.tar.gz" \
		&& tar -xvf redis.tar.gz

2. 构建过程

在完成Dockerfile文件编写后,将当前目录移至Dockerfile所在的目录

1
docker build -t nginx:test .			#nginx是镜像名,test是标签

最后一个 .代表上下文路径。由于我们在构建镜像时,有使用本机文件的需求。因此,在构建时,本机将路径下的所有文件发送给docker引擎,由docker引擎完成构建

3. 指令介绍

3.1 COPY

复制指令,从上下文目录中复制文件或者目录到容器的指定路径

1
2
COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]

[–chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。

**<源路径>**:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

1
2
COPY hom* /mydir/
COPY hom?.txt /mydir/

**<目标路径>**:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

3.2 CMD

类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

  • CMD 在docker run 时运行。
  • RUN 是在 docker build。

作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

1
2
3
CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

3.3 ENV

设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

格式:

1
2
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

1
2
3
4
ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

3.4 ARG

构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 –build-arg <参数名>=<值> 来覆盖。

格式:

1
ARG <参数名>[=<默认值>]

3.5 VOLUME

定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

作用:

  • 避免重要的数据,因容器重启而丢失,这是非常致命的。
  • 避免容器不断变大。

格式:

1
2
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

3.6 EXPOSE

仅仅只是声明端口。

作用:

  • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
  • 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

格式:

1
EXPOSE <端口1> [<端口2>...]

3.7 WORKDIR

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

格式:

1
WORKDIR <工作目录路径>

3.8 USER

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

格式:

1
USER <用户名>[:<用户组>]

3.9 HEALTHCHECK

用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

格式:

1
2
3
4
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

3.10 ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:

1
ONBUILD <其它指令>

六、Docker Compose

Compose是用于定义和运行多容器Docker应用程序的工具。通过Compose,使用YML文件配置应用程序需要的所有服务。

  • 使用Dockerfile定义应用程序的环境
  • 使用docker-compose.yml定义构成应用程序的服务,使其可以在隔离环境中一起运行
  • 执行docker-compose up 命令来启动并运行整个应用程序

1. 安装

linux安装:https://www.runoob.com/docker/docker-compose.html

macOS/windows安装:安装桌面版Docker Toolbox已自带

2.

七、各容器使用实例

1.Mysql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 拉取特定版本的mysql
docker pull mysql:versionid

# 以mysqlimage为镜像,创建名为containerName的mysql容器,mysql密码为admin
docker run --name containerName -e MYSQL_ROOT_PASSWORD=admin -d -p 3306:3306 mysqlimgae

# 将需要导入的sql脚本复制进容器中
docker cp sourcePath/fileName containerName:targetPath/fileName

# 以后台运行不退出方式进入容器
docker exec -it containerName bash

# 输入密码进入mysql
mysql -u root -p

# 创建数据库
create database

# 使用创建的数据库
use database

# 导入脚本
source targetPath/fileName

2. RabbitMQ

1
2
3
4
5
# -d 以后台方式打开, --hostnanme 指定hostname, --name指定name
# RABBITMQ_DEFAULT_USER创建用户为root,RABBITMQ_DEFAULT_PASS密码为admin,-p 将mq端口号映射到本地
docker run -d --hostname my-rabbit --name myrabbit -e RABBITMQ_DEFAULT_USER=root -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672 rabbitmq:management
# 浏览器访问暴露的端口
localhost:15672
1
2
3
4
5
6
7
docker run -p 9200:9200 -p 9300:9300 -d --name es_643 elasticsearch:6.4.3

# 进入elastic search
docker exec -it es_643 /bin/bash

# 下载版本对应的分词器
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.4.3/elasticsearch-analysis-ik-6.4.3.zip

4.redis

1
2
3
4
5
docker pull redis:latest

docker run -itd --name myredis -p 6379:6379 redis

docker exec -it redis-test /bin/bash