Docker基础

Docker

[TOC]

Docker 仓库:https://hub.docker.com/explore/

Docker简介

一次编译,到处运行 JVM
hypervisor:一种运行在物理服务器和操作系统之间的中间层软件,可以允许多个操作系统和应用共享一套基础物理硬件。可以将hypervisor看做是虚拟环境中的“元”操作系统,可以协调访问服务器上的所有物理设备和虚拟机,所以又称为虚拟机监视器(virtual machine monitor)。
阿里云、腾讯云等的架构

云架构.png

虚拟机与Docker的区别:
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

virtualization.png
docker.png

对比

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱于原生
系统支持量 单机支持上千个容器 一般为几十个

虚拟机里无法运行虚拟机

Docker引擎

Docker 引擎是一个包含以下主要组件的客户端服务器应用程序

  • 一种服务器,它是一种称为守护进程并且长时间运行的程序
  • REST API用于指定程序可以用来与守护进程通信的接口,并指示它做什么
  • 一个命令行界面(CLI)工具的客户端
    • docker image
    • docker container
Docker引擎组件.png

Docker 使用客户端-服务器 (C/S) 架构模式,使用远程 API 来管理和创建 Docker 容器。
Docker 容器通过 Docker 镜像来创建,容器与镜像的关系类似于面向对象编程中的对象与类,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

Docker架构.png
标题 说明
镜像(Images) Docker镜像是用于创建Docker容器的模板
容器(Container) 容器是独立运行的一个或一组应用
客户端(Client) Docker客户端通过命令行或者其他工具使用Docker API与Docker的守护进程通信
主机(Host) 一个物理或者虚拟的机器用于执行Docker守护进程和容器
仓库(Registry) Docker仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。
Docker Machine Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。

前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

一个 Docker Registry 中可以包含多个仓库Repository);每个仓库可以包含多个标签Tag);每个标签对应一个镜像。

学习公有仓库怎么用,私有仓库怎么建。

Docker镜像加速器

对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件)

{
  "registry-mirrors": [
    "https://registry.docker-cn.com"
  ]
}

之后重新启动服务

sudo systemctl daemon-reload
sudo systemctl restart docker

检查生效,执行docker info,看是否有以下内容

Registry Mirrors:
 https://registry.docker-cn.com/

Ubuntu安装Docker

使用脚本自动安装,在测试开发环境中Docker官方为了简化安装流程,提供了一套便捷的安装脚本:

curl -fsSL get.docker.com -o get-docker.sh
# 可能会出现 404 错误,请移步下面的特别说明
# sudo sh get-docker.sh --mirror Aliyun  #阿里云目前有问题
sudo sh get-docker.sh --mirror AzureChinaCloud

执行这个命令后,脚本就会自动将一切准备工作做好,并且把Docker CE的Edge版本安装在系统中。

启动Docker CE

sudo systemctl enable docker
sudo systemctl start docker

建立用户组:

默认情况下,docker 命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。

  • 建立docker
sudo groupadd docker
  • 将当前用户加入docker组
sudo usermod -aG docker $USER

使用Docker镜像

获取、列出、删除镜像

docker pull:从Docker镜像仓库获取镜像,命令格式如下:

docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
  • Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。
  • 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
$ docker pull ubuntu:16.04
# 上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 
# ubuntu:16.04,因此将会获取官方镜像 library/ubuntu 仓库中标签为 16.04 的镜像。

$ docker image ls  # 显示顶层镜像
$ docker image ls -a  # 显示所有镜像(包括顶层镜像和中间镜像)
#无标签的镜像很多都是中间层镜像,是其它镜像所依赖的镜像。这些无标签镜像不应该删除,否则会导致上层镜像因为依赖丢失而出错

$ docker image ls ubuntu # 根据仓库名列出镜像
$ docker image ls ubuntu:16.04 # 列出某个特定的镜像

$ docker ps # 查看运行中的容器
$ docker ps -a  # 查看所有容器

$ docker run -it --rm \   # 交换的方式运行容器
    ubuntu:16.04 \
    bash
    
$ docker rm 容器id  # 删除容器

$ docker system df  # 查看镜像、容器、数据卷所占用的空间

$ docker image ls -f dangling=true # 显示虚悬镜像
$ docker image prune  # 删除虚悬镜像

$ docker image rm [选项] <镜像>  # 删除镜像,<镜像> 可以是 镜像短 ID、镜像长 ID、镜像名 或者 镜像摘要

docker run 就是运行容器的命令,我们这里简要的说明一下上面用到的参数。

  • -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退出容器

使用Dockerfile定制镜像

Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

$ docker pull tomcat
$ docker run -it tomcat bash
$ ls -al  #ll命令不能用
$ cd webapps/
$ ls -al
$ cd ROOT/
$ ls -al
# tomcat下ll、vi命令不能用,cat、echo能使用
$ exit # 退出
$ docker run -p 8080:8080 tomcat

自己装的软件必须放到 usr/local/目录下(国际惯例)

区分:

  • 交互的方式启动容器
$ docker run -it tomcat bash
#交互式启动容器进行修改修改不保存
  • 交互的方式进入容器
$ docker run -p 8080:8080 tomcat
# 再开一个命令行
$ docker exec -it <容器id> bash
$ cd webapps/Root/
$ echo "Hello Docker Tomcat" >> index.jsp

docker run :创建一个新的容器并运行一个命令

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

示例:Dockerfile定制tomcat镜像

# 创建docker目录(存放文件)
cd /usr/local/
mkdir docker
cd docker/
mkdir tomcat
cd tomcat/
vi Dockerfile

编写Dockerfile脚本:

FROM tomcat

WORKDIR /usr/local/tomcat/webapps/ROOT/
RUN rm -fr *
RUN echo "Hello Docker" > /usr/local/tomcat/webapps/ROOT/index.html
  • FROM 指定基础镜像(必备,必须是第一条指令)
  • RUN 执行命令行命令
    • shell格式:RUN <命令>,就像直接在命令行中输入的命令一样

构建镜像:(在Dockerfile文件所在目录执行)

  • 命令:docker build [选项] <上下文路径/URL/->
docker build -t myshop .
# repository名为myshop
# 不带标签表示latest
# .表示当前目录,告诉命令Dockerfile在哪,这个 . 实际上是在指定上下文的目录,docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。

以交互方式进入容器:

docker run -it --rm myshop bash

启动myshop

docker run -p 8080:8080 myshop
Docker指令详解

示例:在docker部署一个项目

1.拷贝 myshop.zip -> tomcat/webapps/ROOT

2.修改访问端口号为80

FROM tomcat

WORKDIR usr/local/tomcat/webapps/ROOT/

RUN rm -fr *  # 先把ROOT目录下的东西删除,以免冲突出错

# my-shop-wed-admin-1.0.0.SNAPSHOT.zip与Dockerfile在同一个目录下
COPY my-shop-wed-admin-1.0.0.SNAPSHOT.zip .  # .指当前目录,即WORKDIR

RUN unzip my-shop-wed-admin-1.0.0.SNAPSHOT.zip

RUN rm -fr my-shop-wed-admin-1.0.0.SNAPSHOT.zip

docker build -t myshop

  • WORKDIR 指定工作目录:WORKDIR <工作目录路径>

(注意:每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更,如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令。)

RUN 启动容器1
    cd app
RUN 启动容器2
    镜像本身指定的工作目录中  # 可以通过docker run -it --rm tomcat bash 进入容器查看
# 当指定工作目录后,docker run -it --rm tomcat bash进入的即为WORKDIR

命令解释docker run -p 8080:8080 tomcat

  • 8080:8080 即将宿主机的8080端口映射到容器的8080端口

重启容器:docker restart <容器>

操作Docker容器

容器是独立运行的一个或一组应用,以及它们的运行状态环境。

启动容器

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另一个是将在终止状态(stopped)的容器重新启动。因为Docker的容器实在太轻量级了,很多时候用户都是随时删除和新建容器。

新建并启动容器

$ docker run -it --rm ubuntu:16.04 bash

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

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

启动已终止容器

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

以交互的方式进入容器$ docker exec -it <容器id> bash

终止容器docker container stop <容器>

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

守护态运行

更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d 参数来实现。

$ docker run -d tomcat

使用-d参数启动后会返回一个唯一的id,也可以通过docker container ls命令来查看容器信息,和docker ps输出信息一样。

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

注: 容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关。

进入容器

在使用 -d 参数时,容器启动后会进入后台。

某些时候需要进入容器进行操作,包括使用 docker attach 命令或 docker exec 命令,推荐大家使用 docker exec 命令,原因会在下面说明。

docker exec 后边可以跟多个参数,这里主要说明 -i -t 参数。

只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。当 -i -t 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。

exec命令的stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 docker exec 的原因。

删除容器

删除一个处于终止状态的容器:docker container rm <容器>

清理所有处于终止状态的容器:docker container prune

数据卷

Docker Container 可以认为是面向对象中的对象

  • 对象一旦被销毁,数据就不存在了
  • 容器一旦被销毁,则容器内的数据将一并被删除
  • 服务器中的图片也会一并被删除
  • 容器中的数据不是持久化状态的

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS(UNIX文件系统??),可以提供很多有用的特性:

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

使用示例:

cd /usr/local/docker/tomcat/
mkdir ROOT # 需要创建个ROOT目录来替换容器中的ROOT目录
cd ROOT/
vi index.html
# -v 后 左边的是宿主机目录,右边的是容器目录
docker run -p 8080:8080 --name tomcat -d -v /usr/local/docker/tomcat/ROOT/:/usr/local/tomcat/webapps/ROOT/ tomcat
docker ps
docker exec -it tomcat bash
cd webapps/ROOT/
ls -al # 发现使用的是宿主机目录下的文件

docker run -p 8081:8080 --name tomcat2 -d -v /usr/local/docker/tomcat/ROOT/:/usr/local/tomcat/webapps/ROOT/ tomcat  # 贡共享数据卷

Docker 构建数据库

docker pull mysql # 会拉取最新版本
docker pull mysql:5.7.24  # 建议使用这个版本

# 运行容器
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.24

# 最新版启动方式已经改变,上述为5.x版本的启动方式

docker exec -it mysql bash

命令参数:

  • -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用户的密码

将容器里的文件复制到宿主机

# 修改配置文件
docker run -p 3306:3306 --name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.7.24

docker exec -it mysql bash

whereis mysql
cd /etc/mysql/conf.d/
cat mysqldump.cnf # 查看mysql容量
echo "max_allowed_packet=128M" >> mysqld.cnf  # 修改mysql容量
cat mysqld.cnf # 查看修改
exit
docker restart mysql # 重启容器

# 将容器里的文件复制到宿主机
cd /usr/local/docker/mysql/conf
docker cp mysql:/etc/mysql .  # 将容器为mysql的/etc/mysql文件夹拷贝到.当前目录下
mv *.* ..
cd ..
rm -fr mysql

docker stop <容器>
docker rm -f <容器>

# 运行容器
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.24

项目的容器化部署

cd /usr/local/docker/tomcat/ROOT/
rm -fr index.html
cd ..
cp my-shop-web.admin-1.0.0-SNAPSHOT.zip ROOT/
cd /usr/local/docker/tomcat/ROOT/
ll
unzip my-shop-web.admin-1.0.0-SNAPSHOT.zip
rm -fr my-shop-web.admin-1.0.0-SNAPSHOT.zip
ll
cd ..
# 修改项目配置文件
cd ./ROOT/WEB-INF/classes
ll
vi myshop.properties
cd /usr/local/docker/tomcat/
docker run -p 8080:8080 --name myshop -v /usr/local/docker/tomcat/ROOT/:/usr/local/tomcat/webapps/ROOT/ -d tomcat

# 查看日志
docker logs myshop
# 监听日志
docker logs -f myshop

Docker 批量操作容器或镜像

$ docker container rm  [OPTIONS]  CONTAINER [CONTAINER...]
# 如果要删除的 container 还是运行状态,要先停止容器
$ docker  containt  stop   ffe5e
$ docker   container  rm  ffe5e

# 清理所有处于终止状态的容器
$ docker container prune
$ docker image rm [选项] <镜像1> [<镜像2> ...]

<镜像> 可以是 镜像短 ID镜像长 ID镜像名 或者 镜像摘要

批量获取 容器ID 和 镜像ID

# 批量获取 容器ID
$ docker container ls -a -q

# 批量获取 镜像ID
$ docker image ls -a -q

批量停止容器

$ docker container   stop   $(docker  container  ls   -a  -q)

批量删除容器和镜像

# 批量删除容器:
$ docker container rm $(docker container ls -a -q)
# 清理所有处于终止状态的容器
$ docker container prune

# 批量删除镜像:
$ docker image rm $(docker image ls -a -q)

自定义

将要删除的容器名写到一个文档,然后根据提供的名字,再结合 grep 、awk 等命令,就可以轻松地获取准确的 ID 号了。只要获取了 ID 号,就可以用上面的方法将它们删除。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容