Docker基础

1. Docker简介

1.1 Docker是什么

1.2 传统虚拟机和容器的区别

Docker并非是一个通用的容器工具,它依赖于已存在并运行的Linux内核环境。

Docker实质上是在已经运行的Linux下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的Linux主机。因此,Docke必须部署在Linux内核的系统上,如果其他系统想要部署Docker就必须按照一个虚拟的Linux环境。

在Windows上部署Docker的方法就是先安装一个虚拟机,并在Linux虚拟机中运行Docker。

img

1.3 Docker三要素

1.4 Docker平台架构

1.5 为什么Docker比虚拟机更快?

  1. docker有着比虚拟机更少的抽象层

由于docker不需要虚拟机实现资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。

  1. docker利用的是宿主机的内核,而不需要加载整个操作系统内核

2. Docker安装

2.1 Ubuntu安装

  1. **官网:**https://docs.docker.com/engine/install/ubuntu/
  2. 确定系统版本满足要求

img

  1. 卸载旧版本
  • 卸载 Docker Engine、CLI、containerd 和 Docker Compose 包
sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-compose-plugin
  • 主机上的镜像、容器、卷或自定义配置文件不会自动删除。删除所有镜像、容器和卷:
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
  1. 安装gcc、gcc+
  • sudo apt-get install -y gcc
  • sudo apt-get install -y g++
  1. 使用Docker仓库安装

Docker版本分为两个:Docker Community Edition (CE) 和 Docker Enterprise Edition (EE)。Docker CE社区版本适合个人用户使用。

在新主机上首次安装 Docker Engine 之前,您需要设置 Docker 仓库。之后,您可以从仓库安装和更新 Docker。

  • 设置stable仓库

更新apt包索引并安装包以允许apt通过 HTTPS 使用docker仓库库:

sudo apt-get update
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

添加 Docker 的官方 GPG 密钥(可能会出现警告,但是可以不用理会):

sudo mkdir -p /etc/apt/keyrings
// Docker阿里云源
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

使用以下命令设置stable仓库:

sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

注:官网推荐的Docker仓库在国内访问很慢,很容易超时,需要设置成国内的镜像仓库。

阿里云Docker CE镜像:https://mirrors.aliyun.com/docker-ce/?spm=a2c6h.13651104.0.0.3dd53317lJiUwO

  • 安装Docker引擎

更新apt索引:sudo apt-get update

安装 Docker Engine、containerd 和 Docker Compose:

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  • 验证Docker引擎是否安装成功

查看docker版本:docker version

运行hello-world镜像:sudo docker run hello-world

2.2 Docker引擎安装后的配置

  1. 以非root用户身份管理Docker

Docker守护进程绑定到Unix套接字,而不是TCP端口。默认情况下,root是拥有Unix套接字的用户,其他用户只能使用 sudo访问Unix套接字。Docker守护进程始终以root用户身份运行。

如果您不想在docker命令前加上sudo,请创建一个名为 的 Unix 组docker并将用户添加到其中。当 Docker 守护进程启动时,它会创建一个可供docker组成员访问的 Unix 套接字。在某些 Linux 发行版上,系统会在使用包管理器安装 Docker Engine 时自动创建此组。在这种情况下,您无需手动创建组。

  • 创建docke组:sudo groupadd docker
  • 将用户添加到docker组中:sudo usermod -aG docker $USER
  • 注销并重新登录系统或者运行$ newgrp docker命令来激活对组的更改。
  • 验证是否可以以非root身份使用docker: $ docker run hello-world
  1. 配置Docker以使用systemd启动

许多现代 Linux 发行版使用systemd来管理在系统启动时启动哪些服务。在 Debian 和 Ubuntu 上,Docker 服务默认在启动时启动。要使用 systemd 为其他 Linux 发行版在启动时自动启动 Docker 和 containerd,请运行以下命令:

sudo systemctl enable docker.service
sudo systemctl enable containerd.service

要停止此行为,请改用disable:

sudo systemctl disable docker.service
sudo systemctl disable containerd.service

3. Docker常用命令

3.1 帮助启动类命令

  • 启动docker:systemctl start docker
  • 停止docker:systemctl stop docker
  • 重启docker:systemctl restart docker
  • 查看docker状态:systemctl status docker
  • 设置开机启动:systemctl enable docker,Ubuntu安装docker默认开机启动。
  • 关闭开机启动:systemctl disable docker
  • 查看docker概要信息:docker info
  • 查看docker总体帮助文档:docker --help
  • 查看docker命令帮助文档:docker 命令 --help

3.2 镜像命令

  1. docker images:列出本地主机镜像。
  • docker images -a:列出本地所有镜像(包括历史镜像层)。
  • docker images -q:只显示镜像ID。

img

  • REPOSITORY:镜像的仓库源
  • TAG:镜像的标签
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小

同一仓库源可以有多个TAG版本,代表这个仓库源的不同版本,使用REPOSITORY:TAG来定义不同的镜像。

如果不指定镜像的版本标签,docker将默认使用latest镜像。

  1. docker search 镜像:查看镜像是否存在。

img

OOFICIAL发布的镜像NAME只有镜像名,而个人或组织发布的镜像NAME为组织 名/镜像名,镜像首选官方镜像。

  • docker search --limit n 镜像:限定显示的镜像个数。
  1. 拉取镜像:docker pull 镜像:TAG,不指定TAG则默认latest。
  2. docker system df:查看镜像/容器/数据卷所占空间。

img

  1. docker rmi 镜像名:TAG/镜像ID:删除镜像,可以接多个镜像进行删除。
  • docker rmi -f 镜像:强制删除,未停止运行的容器不能删除其镜像,可以使用强制删除。
  • docker -rmi -f $(docker images -qa):删除全部镜像。
  1. docker save:将镜像保存到文件中。
  • docker save -o my-image.tar my-image:latest
  1. docker load:从文件中加载镜像。
  • docker load -i my-image.tar
  • 注意,docker load命令仅适用于加载镜像,不能用于加载容器。如果想要加载容器,可以使用docker import命令。

3.3 容器命令

  1. 新建+启动容器:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

OPTIONS:

  • --name="容器新名字":为容器指定一个名称,不指定则随机分配名称,=可以省略。
  • -d:后台运行容器并返回容器ID,即启动守护式容器。
  • -i:以交互模式运行容器,通常与-t同时使用。
  • -t:为容器重新分配一个伪输入终端,通常与-i同时使用,即启动交互式容器。
  • -P:随机端口映射。
  • -p:指定端口映射。
参数 说明
-p hostPort:cotainerPort 端口映射 -p 8080:80
-p ip:hostPort:cotainerPort 配置监听地址 -p 10.0.0.100:8080:80

命令示例:

docker run --name=ubuntu -it ubuntu /bin/bash,用bash交互式运行ubuntu,/bin/bash可以省略。如果要退出终端,直接输入exit,容器也会停止。

docker run --name=Redis -p 8080:80 -d redis,后台运行redis,映射到主机8080端口。

  1. 列出所有正在运行的容器:docker ps [OPTIONS]
  • -a:列出当前所有正在运行的容器+历史上运行过的容器。
  • -l:显示最近创建的容器,包括已经停止的容器。
  • -n:显示最近n个创建的容器,包括已经停止的容器。
  • -q:静默模式,只显示正在运行的容器编号。
  1. 退出容器:exit和ctrl+p+q两种退出方式。
  • exit:通过exit退出,容器也会停止。
  • ctrl+p+q:通过ctrl+p+q退出,容器不会停止。
  1. 启动已停止运行的容器:docker start 容器ID或容器名
  2. 重启容器:docker restart 容器ID或容器名
  3. 停止容器:docker stop 容器ID或容器名
  4. 强制停止容器:docker kill 容器ID或容器名
  5. 删除已停止的容器:docker rm 容器ID或容器名,可一次性停止多个。
  • docker rm -f 容器ID或容器名:强制删除容器。
  • docker rm -f $(docker ps -a -q):强制删除所有容器。
  • docker ps -a -q | xargs docker rm:删除所有容器。
  1. 后台启动容器注意事项
  • Docker容器后台运行,必须有一个前台进程,容器运行的命令如果不是一直挂起的命令(比如运行top,tail),容器启动后会马上自动退出。

比如docker run -d ubuntu后台启动一个ubuntu容器,然后通过docker ps -a进行查看,发现容器已经退出。所以,在进行docker run后,要进行docker ps查看容器是否真正运行,run和ps命令一般结合使用。

img

出现这个问题是由于docker机制的问题,比如web容器,以nginx为例,正常情况,只需要service nginx start以后台进程模式启动nginx即可,但是nginx启动后会马上自杀,因为它觉得不需要使用到它。

所以,最佳解决方案是,将要运行的容器以前台进程的方式运行,常见的就是命令行模式,表示还有交互操作,则容器不会自杀。对于redis,mysql这种应用,容器不会自杀,应当以后台方式运行。

  1. 查看容器日志:docker logs 容器ID
  • docker logs -f 容器ID:跟踪日志信息。
  • docker logs -f -n 行数:实时显示最后n行日志信息。
  1. 查看容器内的进程运行情况:docker top 容器ID
  2. 查看容器内部细节:docker inspect 容器ID
  3. 进入正在运行的容器并以命令行交互
  • docker exec -it 容器ID
  • docker attach 容器ID
  • 两者区别:attach直接进入容器启动命令行终端,不会启动新的进程,用exit退出,会导致容器停止。exec是在容器中打开新的终端,并且可以启动新的进程,用exit退出,不会导致容器的停止。推荐使用docker exec命令,因为退出终端,不会导致容器停止。
  1. 从容器拷贝文件到主机:docker cp 容器ID:容器内路径 主机路径。容器是一个简易的Linux环境,它的文件系统和linux系统是一样的。

  2. 导入和导出容器

  • docker export 容器ID > 文件名.tar:export导出容器的内容作为一个tar归档文件。
  • cat 文件名.tar | docker import-镜像用户/镜像名:镜像TAG:import导入tar包的内容创建一个新的镜像。
  1. 生成新的镜像:docker commit -m="修改信息" -a="作者" 容器ID 新镜像名:TAG。 示例:ubuntu安装vim后提交新的镜像。
  • 从Hub下载ubuntu原始镜像到本地并运行。
  • 原始的ubuntu是不带vim命令的。
  • 安装vim。
  • commit新镜像:docker commit -m="add vim" -a="sundegan" ubuntu容器ID sundegan/ubuntu:1.1
  • docker images查看本地镜像,发现有一个新的镜像sundegan/ubuntu。
  1. 查看所有容器的资源使用情况:docker stats

4. Docker镜像

镜像是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,把应用程序和配置依赖打包形成一个可交付的运行环境(包括代码、运行时所需的库、环境变量和配置文件等),这个打包好的运行环境就是镜像文 件。只有通过镜像文件才能生成Docker容器实例。

4.1 UnionFS

联合文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层叠加,同时可以将不同的目录挂载到同一个虚拟文件系统下。UnionFS是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像可以制作各种具体的应用镜像。

4.2 Docker镜像加载原理

4.3 为什么Docker镜像要采用分层结构?

5. 本地镜像发布到阿里云

5.1 本地镜像发布到阿里云流程

5.2 镜像的生成方法

5.3 将本地镜像推送到阿里云

5.4 将阿里云上的镜像下载到本地

6. 本地镜像发布到私有库

7. Docker数据卷

7.1 容器数据卷是什么?

卷就是目录或文件,存在于一个或多个容器中,由Docker挂载到容器,但不属于联合文件系统,因此能够绕过联合文件系统提供一些用于持续存储或共享数据的特性。

卷的设计目的就是数据持久化,完全独立于容器的生命周期,因次Docker不会在容器删除时删除其挂载的数据卷。

7.2 容器数据卷能干嘛?

镜像运行后形成容器实例运行,Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。为了能保存数据在docker中我们使用卷。

特点:

  • 数据卷可在容器之间共享或重用数据以及进行数据持久化。
  • 卷中的更改可以直接实时生效。
  • 数据卷中的更改不会包含在镜像的更新中。
  • 数据卷的生命周期一直持续到没有容器使用它为止。

7.3 数据卷案例

  1. 添加容器卷
  • 数据卷挂载命令:docker run -it --privileged=true -v 宿主机绝对目录:容器目录 镜像名

--privileged=true用来开启容器的挂载权限。

-v:表示挂载容器数据卷,可以挂载多份。

docker run -it --privileged=true -v /tmp/myHostData:/tmp/myDockerData ubuntu
  • 查看数据卷是否挂载成功:docker inspect 容器ID

img

  1. 读写规则映射
  • 默认容器内目录可读可写数据卷:docker run -it --privileged=true -v 宿主机绝对目录:容器目录:rw 镜像名rw可省略,默认可读可写。
  • 容器只能读取数据卷:docker run -it --privileged=true -v 宿主机绝对目录:容器目录:ro 镜像名
  1. 卷的继承和共享

容器2继承容器1的卷规则:docker run -it --privileged=true --volumes-from 容器1 容器2,则实现了在容器1、容器2、主机三者间共享容器数据卷。

8. 常规软件安装

8.1 总体步骤

  • 搜索镜像,去官网查看该镜像的使用方法。
  • 拉取镜像
  • 查看镜像
  • 启动镜像:服务端口映射、容器卷配置。

8.2 MySQL

  1. 简单版
  • 运行mysql:docker run -p 3306:3306 --name=mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql-e MYSQL_ROOT_PASSWORD=123456配置MySQL密码为123456。

注意:如果宿主机启动了MySQL会占用3306端口,则会运行失败,需要关闭宿主机中的MySQL。

  • 使用mysql:docker exec -it mysql /bin/bash
  • 登录mysql:mysql -uroot -p

img

  • 远程连接mysql容器

img

简单版MySQL容器安装存在以下问题:

  • Docker容器版MySQL数据库插入中文会报错:Docker默认字符集编码没有进行修改。
  • MySQL容器没有使用容器数据卷进行数据备份,如果误删MySQL容器,则会造成数据丢失。
  1. 实战版
  • 运行MySQL
docker run -d -p 3306:3306 --privileged=true \
-v /Users/sundegan/docker_volume/mysql/log:/var/log/mysql \
-v /Users/sundegan/docker_volume/mysql/data:/var/lib/mysql \
-v /Users/sundegan/docker_volume/mysql/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-test mysql
  • 解决中文乱码,客户端服务端编码都配置为UTF-8。
$ cd /sundegan/docker_volume/mysql/conf
$ vim my.cnf
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
$ cat my.cnf
$ docker restart mysql-test

在修改编码之前建立的数据库,乱码问题依旧存在;只有在修改完编码后新建的数据库才有效。所以建议先修改完字符集编码后再新建数据库。

8.3 Redis

  1. 编写好一个redis.conf配置文件放在宿主机指定目录下,这里为/sundegan/redis/redis.conf。

https://cloud.tencent.com/developer/article/1947475

  1. 运行Redis容器
$ docker run  -p 6379:6379 --name redis \
--privileged=true \
-v /sundegan/redis/redis.conf:/etc/redis/redis.conf \
-v /sundegan/redis/data:/data \
-d redis \
redis-server /etc/redis/redis.conf

redis-server /etc/redis/redis.conf命令指定从/etc/redis/redis.conf读取配置文件。

  1. 使用redis
$ docker exec -it redis /bin/bash
$ redis-cli
  1. 远程连接redis

redis默认只能接受本机的访问请求,redis是需要远程访问的,需要在redis.conf中将bind 127.0.0.1注释掉才能远程连接。

img

See Also