Docker
学习目标:
- 掌握Docker基础知识,理解镜像与容器区别
- 完成Docker安装与启动
- 掌握Docker镜像与容器相关命令
- 掌握Tomcat Nginx等软件常用应用等安装
- 掌握Docker迁移与备份相关命令
- 运用Dockerfile编写创建容器等脚本
- 学会搭建与使用docker私有仓库
1.Docker简介
1.1 什么是虚拟化
在计算机中,虚拟化(Virtualization)是一种资源管理技术。是将计算机等各种实体资源,如服务器、网络、内存及存储等,予以抽象、转化后呈现出来,打破实体结构间的不可切割的障碍,使用户可以比原本的组态更好的方式来应用这些资源。这些资源的新虚拟部分是不受现有资源的架设方式、地域或物理组态所限制。一般所指的虚拟化资源包括 计算能力和资料存储。
在实际生产环境中,虚拟化技术主要用来解决高性能的物理硬件产能过剩和老旧的硬件产能过低的重组重用,透明化底层物理硬件,从而最大化地利用物理硬件。
虚拟化技术种类很多,例如:软件虚拟化、硬件虚拟化、内存虚拟化、网络虚拟化、桌面虚拟化、服务虚拟化、虚拟机等
1.2 什么是Docker
Docker是一个开源项目,Go语言实现。用于创建、管理和编排容器。
Docker项目的目标是:实现轻量级的操作系统虚拟化解决方案。其基础是Linux容器(LXC)等技术。
为什么选择Docker?
(1)更快速的交付和部署。
Docker依赖于“写时复制(copy-on-write)”模型,使修改应用程序也非常迅速。大多数Docker容器只需要不到1秒钟即可启动。由于去除了管理程序等开销,Docker容器拥有很高的性能。
开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码,Docker设计的目的就是加强开发人员写代码的开发环境与应用程序部署的生产环境一致性。
(2)更高效的虚拟化
Docker容器的运行不需要额外的hypervisor支持,它是内核级的虚拟化
(3)更轻松的迁移和扩展
Docker容器几乎可以在任意平台上运行,用户可以把一个应用程序从一个平台直接迁移到另外一个
(4)鼓励使用面向服务的架构
Docker推荐单个容器只运行一个应用程序或进程,这样就形成了一个分布式的应用程序模型。在该种模型下,应用程序或者服务都可以表示为一系列内部互联的容器,从而使分布式部署应用程序,扩展或调试都变得非常简单。(当然一个容器内也可运行多个应用程序)
1.3 容器与虚拟机比较
容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统虚拟化方式则是在硬件层面实现
与传统虚拟机相比,Docker优势体现为:启动速度快、占用体积小
1.4 Docker组件
1.4.1 Docker服务器与客户端
Docker是一个C/S架构程序。Docker客户端只需要向Docker服务器或者守护进程发出请求。Docker提供了一个命令行工具和一整套RESTful API。
1.4.2 🌟Docker镜像 🌟
镜像(image)是构建Docker的基石,镜像也是Docker生命周期中的“构建”部分。镜像是基于联合文件系统的一种层式结构,由一系列指令一步一步构建出来。镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统,同时还包含应用运行所必须的文件和依赖包,体积小,易于分享、存储和更新。
所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上创建新的镜像层。在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合
Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点
Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统
镜像散列值:
1.4.3 🌟Docker容器 🌟
容器:镜像的运行实例
Docker可以帮助你构建和部署容器。
容器(container)基于镜像启动,我们可以认为镜像是Docker生命周期中的构建或打包阶段,而容器则是启动或者执行阶段。
用户可以从单个镜像启动一个或者多容器。
容器的状态变化
1.4.4 Registry 注册中心
Docker用Registry来保存用户构建的镜像,Registry分为公共和私有两种。公共的:Docker Hub,可以分享并保存自己的镜像
1.5 Docker引擎
Docker Engine是用来运行和管理容器的核心软件。其采用模块化设计原则,组件可替换。
容器引擎可以获取系统资源,比如进程树、文件系统以及网格线,接着将资源分割为安全的互相隔离的资源结构
Docker引擎由如下主要的组件构成:Docker客户端,Docker守护进程,containerd以及runc
什么是shim
什么是runc
Docker引擎尽可能实现OCI的规范,例如Docker daemon不再包含任何容器运行时代码,所有的容器运行代码在一个单独的OCI兼容层中实现;默认情况下Docker使用runc来实现。
runc
runc是OCI容器运行时标准的参考实现。runc实质上是一个轻量级的、针对Libcontainer进行包装的命令行交互工具
runc只有一个作用:创建容器,是一个CLI包装器,实质上就是一个独立的容器运行时工具。
containerd
主要任务是容器的生命周期管理 ——start |pause|rm…
Docker引擎技术栈中,containerd位于daemon和runc所在的OCI之间
新容器创建过程
将所有用于启动、管理容器的逻辑和代码从daemon中移除,意味着容器运行时与Docker daemon是解耦的
shim
shim是实现无daemon的容器不可或缺的工具
事实上每次创建容器时,都会fork一个新的runc实例,不过一旦容器创建完毕,对应的runc进程就会退出。
一旦容器进程的父进程runc退出,相关联的containerd-shim进程就会成为容器的父进程。作为其父进程,shim职责如下:
- 保持所有STDIN和STDOUT流是开启状态,从而当daemon重启时,容器不会因为管道的关闭而终止
- 将容器的退出状态反馈给daemon
2.Docker安装与启动
将当前用户加入Docker组,可以不需要每次都用sudo
sudo usermod -aG docker <user>
2.1 在macOS上安装
对于Mac版的Docker,并不是为生产环境而设计,故没有基于原生操作系统中Darwin内核的Docker引擎,在Mac版Docker中,Docker daemon是运行在一个轻量级的Linux VM之上
Mac版Docker安装了Docker引擎(客户端以及服务端守护程序)、Docker Compose、Docker machine 以及Notary命令行
官网下载dmg的即可,镜像源配置在 preferences–Docker Engine里的json里设置
{
"experimental": false,
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com"
],
"features": {
"buildkit": true
}
}
查看docker 概要信息,检查是否配置完成:
$ docker info
2.2 在ubuntu/centOS上安装
编辑文件:
$ vi /etc/docker/daemon.json
在该文件中输入:
{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
}
2.3 Docker的启动与停止
systemctl命令是系统服务管理器指令
启动docker:
$ systemctl start docker
停止docker:
$ systemctl stop docker
重启docker:
$ systemctl restart docker
查看docker状态:
$ systemctl status docker
让docker开机自启
$ systemctl enable docker
3.常用命令
3.1镜像相关命令
3.1.1 查看镜像
docker images
REPOSITORY:镜像名称
TAG:镜像标签 镜像版本区分
IMAGE ID:镜像ID 唯一
CREATED:镜像创建日期(不是获取镜像的日期)
SIZE:镜像大小
这些镜像都存储在Docker宿主机的/var/lib/docker目录下
3.1.2 搜索镜像
docker search 镜像名称
docker search 镜像名称 --filter "is-official=true" #只显示官方镜像
docker search 镜像名称 --limit <number> #显示多少个镜像
NAME:仓库名称
STARS:用户评价,反应一个镜像的受欢迎程度
OFFICIAL:是否官方
AUTOMATED:自动构建,表示该镜像由Docker Hub自动构建流程创建
3.1.3 拉取镜像
拉取镜像就是从中央仓库下载镜像到本地
docker pull 镜像名称
docker image pull <repository>:<tag>
3.1.4 删除镜像
当前镜像有运行中的容器,无法删除
按镜像ID删除镜像
docker rmi 镜像ID
docker image rm 镜像ID
删除所有镜像
docker rmi `docker images -q`
3.1.5 docker images
没有标签的镜像被称为悬虚(dangling)镜像在列表中展示为<none>:<none>
原因:构建新的镜像时,为该镜像打了一个已存在的标签,Dockers会移除旧镜像上的标签。
--filter
:过滤docker images
命令返沪的镜像列表的内容
docker images --filter dangling=true #只会返回dangling镜像
可以通过docker image prune
命令移除全部的dangling镜像
Docker目前支持如下的过滤器:
- dangling 可以指定true或者false
- before/since:需要镜像名称或者ID作为参数,返回之前或之后被创建的全部镜像
- label
下面命令返回全部镜像,但是只显示仓库、标签和大小信息
docker image ls --format "{{.Repository}}: {{.Tag}}: {{.Size}}"
--digests
该参数可在本地查看镜像digest
REPOSITORY TAG DIGEST IMAGE ID SIZE
mysql latest sha256:78800...1c30873 a347a5928046 545MB
3.2容器相关命令
3.2.1 查看容器
查看正在运行的容器
docker ps
docker container ls
查看所有容器
docker ps -a
查看最后一次运行的容器
docker ps -l
查看停止的容器
docker ps -f status=exited
3.2.2 创建与启动容器
创建容器:
docker run
创建容器常用的参数说明
-i :表示运行容器
-t :表示容器启动后会进入其命令行。 加入这两个参数后,容器创建就能登录进去,即分配一个伪终端
–name :为创建的容器命名
-v :表示目录映射关系 (前者是宿主机,后者是映射到宿主机上的目录),可以使用多个 -v做多个目录或者文件映射。注意:最好做目录映射,在宿主机上修改然后共享到容器上。
-d :创建一个守护式容器在后台运行(这样创建容器后不会自动登录容器,如果只加-i -t两个参数,创建容器后就会登录进去)
-p :表示端口映射,前者是宿主机端口,后者是容器内的映射端口。可以使用多个 -p做多个端口映射
(1)交互式方式创建容器
docker run -it --name=容器名称 镜像名称:标签 /bin/bash
docker run -it --name=mycentos centos:7 /bin/bash //如果标签为latest则可以省略
输入后:
[root@2fb130ff2f24 /]#
这时我们通过ps命令查看,发现可以看到启动的容器,状态为启动状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rVbdRcOu-1639558463594)(Docker.assets/image-20210102132616161.png)]
退出当前容器 :exit
(2)以守护式方式创建容器
docker run -di --name=容器名称 镜像名称:标签 /bin/bash
yakiniku@ubuntu:~$ docker run -di --name=mycentos2 centos:7
d4f8e1e97603fdc4a46cc08ed65454a63568cfef101fffd46a4b86a92e9bdab0
登录守护式容器方式:
docker exec -it 容器名称(或容器ID) /bin/bash
3.2.3停止与启动容器
停止容器:
docker stop 容器名称(或者容器ID)
docker kill CONTAINER ID 强制关闭容器
启动容器:
docker start 容器名称(或者容器ID)
3.2.4文件拷贝
宿主机 —> 容器
docker cp 文件/目录 容器名称:容器目录
容器 —> 宿主机
docker cp 容器名称:容器目录 文件/目录
3.2.5 目录挂载
将宿主机的目录与容器内的目录进行映射,通过修改宿主机某个目录的文件而去影响容器
可以将配置文件做映射
创建容器,添加-v 宿主机目录 : 容器目录
,例如
docker run -di -v /usr/local/myhtml:/usr/local/myhtml --name=mycentos3 centos:7
如果共享的是多级目录,可能会出现权限不足的提示,这是因为centos7中的安全模块selinux把权限禁掉了,此时可添加参数 -privileged=true
来解决挂载的目录没有权限的问题
3.2.6 查看容器IP地址
可以通过如下命令查看容器运行的各种数据
docker inspect 容器名称(容器ID)
也可以执行如下命令直接输出IP地址
--format
提取所需要的信息
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称(容器ID)
3.2.7 删除容器
停止容器—>删除容器—>删除镜像
无法删除正在允许的容器
就算容器被删除了,如果将容器数据存储在卷(volume)中,数据也会被保存下来。
docker rm 容器名称(容器ID)
docker rm 容器名称(容器ID) -f #强制删除
$() #删除全部容器
docker stop命令向容器内的PID 1进程发送了SIGTERM信号
3.2.8 登录守护容器与退出
登录:
docker exec -it 容器名称(或容器ID) /bin/bash
退出:在容器中输入如下命令
exit
4.应用部署
4.1MySQL部署
docker search mysql # 查看有哪些mysql的镜像
docker pull centos/mysql-57-centos7 #拉取镜像
docker run -di --name=tensquare_mysql -p 33306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql #创建容器
-p
:端口映射, 宿主机映射端口:容器运行端口
-e
:添加环境变量,MYSQL_ROOT_PASSWORD 是root用户的登录密码
docker exec -it tensquare_mysql /bin/bash #进入mysql容器
mysql -u root -p #登录mysql
4.2Tomcat部署
docker pull tomcat:7-jre7 #拉取镜像
docker run -di --name=mytomcat -p 9000:8080 -v /usr/local/webapps:/usr/local/tomcat/webapps tomcat:7-jre7
4.3Nginx部署
docker pull nginx #拉取镜像
docker run -di --name=mynginx -p 80:80 nginx #运行容器
启动后提示80端口被占用,官方的nginx镜像,已经启动了,此时不能再在80上启动另一个
cd /etc/nginx
cat nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf; #导入另外的配置 可以在不同的地方写配置文件,通过 include导入
}
进入/etc/nginx/conf.d
打开default.conf
location / {
root /usr/share/nginx/html; # 可以看到root的目录
index index.html index.htm;
}
4.4Redis部署
docker pull redis #拉取镜像
docker run -di --name=myredis -p 6379:6379 redis #运行容器
5.迁移与备份
docker commit :从容器创建一个新的镜像
5.1 容器保存为镜像
docker commit [OPTIONS] 容器名称 镜像名称[:TAG]
docker commit mynginx mynginx_i
5.2 镜像备份
导出为文件
docker save -o mynginx.tar mynginx_i
5.3 镜像恢复与迁移
docker load -i mynginx.tar
-i
输入的文件
6.Dockerfile
6.1 什么是Dockerfile
Dockerfile是由一系列命令和参数构成的脚本。这些命令应用于基础镜像并最终创建一个新的镜像。
优点:
- 对于开发人员,可以为开发团队提供一个完全一致的开发环境
- 对于测试人员,可以直接拿开发时构建的镜像或通过Dockersfile文件构建一个新的镜像开始工作
- 对于运维人员,在部署时,可以实现应用的无缝移植
6.2常用命令
命令 | 作用 |
---|---|
FROM image_name:tag | 基于某个镜像来创建,前提是存在 |
MAINTAINER user_name | 声明镜像的创建者 |
ENV key value | 设置环境变量(可以多条) |
RUN command | 核心部分 ,在docker build执行 |
CMD command | 类似RUN指令,在docker run时执行 |
ADD source_dir/file dest_dir/file | 将宿主机的文件复制到容器内,如果是一个压缩文件,将会在复制后启动解压 |
COPY source dir/file | 和ADD相似,但是不能解压缩 |
WORKDIR path_dir | 设置工作目录 |
1.RUN指令
RUN:用于执行后面跟着的命令行命令。有以下两种格式
shell格式:
RUN <命令行命令> #在终端操作的shell命令
exec格式:
RUN ["可执行文件","参数1","参数2"]
注意:Dockerfile的指令每执行一次都会在docker上新建一层。所以过多无意义的层,会造成镜像膨胀过大。
FROM centos
RUN yum install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos
RUN yum install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
可以用&&
符号连接命令,这样只会创建一层镜像
2.构建镜像
The docker build
command builds Docker images from a Dockerfile and a “context”
练习 :创建jdk8镜像
yakiniku@ubuntu:/usr/local/dockerjdk8$ cat Dockerfile
#指定基础镜像
FROM centos:7
#指定镜像创建者
MAINTAINER yakiniku
WORKDIR /usr
#创建目录
RUN mkdir /usr/local/java
ADD jdk-8u271-linux-x64.tar.gz /usr/local/java
#创建环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_181
ENV JRE_HOME $JAVA_HOME/jre
ENV PATH $JAVA_HOME/bin:$PATH
docker build -t 'jdk1.8' . # .代表当前目录,必须含有Dockerfie的目录 告诉Docker去当前目录找Dockerfile
注意:镜像必须全为小写字母
2.1上下文路径
.
是上下文路径,是指docker在构建镜像,有时要使用到宿主机的文件(比如复制),docker build命令得知该路径后,会将路径下的所有内容打包。
解析:docker运行模式是C/S,本机是C,docker引擎是S。实际构建过程在docker引擎下完成的,所以无法用到本机文件,这就需要我们把本机指定目录下的文件一起打包提供给docker引擎使用。
注意:上下文路径不要放无用文件,因为会打包发送给docker引擎,如果文件过多会造成过程缓慢
7.Docker私有仓库
企业内部使用,存放docker镜像。存放自己开发的企业级应用,在一个局域网内共享镜像。
有两种搭建方式,一个是registry,这也是一个容器。第二种是harbor
7.1registry
7.1.1私有仓库搭建与配置
(1)拉取私有仓库镜像
docker pull registry
(2)启动私有仓库容器
Registry服务默认会将上传的镜像保存在容器的/var/lib/registry,我们可以也可以将宿主机的/opt/registry目录挂载到该目录
docker run -di --name=registry -p 5000:5000 registry
or
docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --name myregistry registry:2
(3)打开浏览器以下连接后 看到{"repositories":[]}
表示私有仓库搭建成功
http://localhost:5000/v2/_catalog
(4)修改daemon.json
vi /etc/docker/daemon.json
添加以下内容:让docker信任私有仓库地址
{"insecure-repositories":["localhost"]}
(5)重启docker服务
systemctl restart docker
7.1.2镜像上传至私有仓库
(1)标记镜像为私有仓库的镜像 可以看到IMAGE ID 是一样的
yakiniku@ubuntu:~$ docker tag jdk1.8 localhost:5000/jdk1.8
yakiniku@ubuntu:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
jdk1.8 latest afc6af2309a9 22 hours ago 559MB
localhost:5000/jdk1.8 latest afc6af2309a9 22 hours ago 559MB
(2) 上传标记的镜像
yakiniku@ubuntu:~$ docker push localhost:5000/jdk1.8
The push refers to repository [localhost:5000/jdk1.8]
2d68aedeed3f: Pushed
ad55eb485ac7: Pushed
174f56854903: Pushed
latest: digest: sha256:1a9fc7...5141ab size: 949
docker tag: 标记本地镜像,将其归入某一仓库
docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
7.2 Harbor的搭建
Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,harbor使用的是官方的docker registry(v2 命名是distribution)服务去完成,harbor在其基础上,增加了一些安全、访问控制、管理的功能。