Docker知识
部署方式演变

传统部署时代
早期,企业直接将应用程序部署在物理机上。由于物理机上不能为应用程序定义资源使用边界,我们也就很难合理地分配计算资源。例如:如果多个应用程序运行在同一台物理机上,可能发生这样的情况:其中的一个应用程序消耗了大多数的计算资源,导致其他应用程序不能正常运行。应对此问题的一种解决办法是,将每一个应用程序运行在不同的物理机上。然而,这种做法无法大规模实施,因为资源利用率很低,且企业维护更多物理机的成本昂贵。
虚拟化部署时代
- 针对上述问题,虚拟化技术应运而生。用户可以在单台物理机的CPU上运行多个虚拟机(Virtual Machine)。
- 虚拟化技术使得应用程序被虚拟机相互分隔开,限制了应用程序之间的非法访问,进而提供了一定程度的安全性。
- 虚拟化技术提高了物理机的资源利用率,可以更容易地安装或更新应用程序,降低了硬件成本,因此可以更好地规模化实施。
- 每一个虚拟机可以认为是被虚拟化的物理机之上的一台完整的机器,其中运行了一台机器的所有组件,包括虚拟机自身的操作系统。

容器化部署时代
容器与虚拟机类似,但是降低了隔离层级,共享了操作系统。因此,容器可以认为是轻量级的。
与虚拟机相似,每个容器拥有自己的文件系统、CPU、内存、进程空间等
运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦
容器化的应用程序可以跨云服务商、跨Linux操作系统发行版进行部署

什么是docker
Docker 是一个开源的应用容器引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在本地编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack 集群和其他的基础应用平台。
简单的理解,Docker类似于集装箱,各式各样的货物,经过集装箱的标准化进行托管,而集装箱和集装箱之间没有影响。也就是说,Docker平台就是一个软件集装箱化平台,这就意味着我们自己可以构建应用程序,将其依赖关系一起打包到一个容器中,然后这容器就很容易运送到其他的机器上进行运行,而且非常易于装载、复制、移除,非常适合软件弹性架构。
docker跟虚拟机区别
Docker可以让一个应用在任何操作系统中非常方便的运行。而以前我们接触的虚拟机,也能在一个操作系统中,运行另外一个操作系统,保护系统中的任何应用。
两者有什么差异呢?
虚拟机(virtual machine)是在操作系统中模拟硬件设备,然后运行另一个操作系统,比如在 Windows 系统里面运行 Ubuntu 系统,这样就可以运行任意的Ubuntu应用了。
Docker仅仅是封装函数库,并没有模拟完整的操作系统,如图:

由于容器所需的资源要少得多(例如,它们不需要一个完整的 OS),所以它们易于部署且可快速启动。这使你能够具有更高的密度,也就是说,这允许你在同一硬件单元上运行更多服务,从而降低了成本
对比
docker 好处(节省项目环境部署时间)
场景1:单项目打包
每次部署项目到测试、生产等环境,都要部署一大堆依赖的软件、工具,而且部署期间出现问题几率很大,不经意就花费了很长时间。
Docker主要理念就是环境打包部署,可在任意Docker Engine运行。前期我们只需要将每个项目环境打包到镜像,push到镜像仓库,当有需要部署这个项目时,直接pull镜像启动容器,这个项目就可以访问了!一次构建多次部署,一劳永逸。
场景二:环境一致性
开发工程师在Windows系统上开发项目,测试、生产环境操作系统都是Linux系统,这就产生了环境不一致的情况:项目在开发电脑本地运行没问题,到了测试或生产环境就运行不起来,解决这问题最好方式就是这三处环境保持一致。软件版本、操作系统、物理机、云主机……试想下,能做到吗?
Docker将项目环境打包成镜像,可以在任何Docker Engine上浪。此时Docker就是我们这些项目的基石,Docker可移植性,保持运行状态一致性,可想而知,是否更容易解决问题呢?
场景三:持续集成
*一个项目版本快速迭代的测试场景,需要一个合理的CI(持续集成)/CD(持续部署)环境支撑。CI/CD是一个周期性自动化项目测试流程,包括构建、部署、测试、发布等工作,很少需要人工干预。
项目测试流程大致如下图:

Docker结合Jenkins构建持续集成环境大致如下图:

Docker在上面这个图的作用是项目镜像构建和快速部署,打通测试环境与生产环境,高度保持多个环境之间一致性。
- 场景四:微服务
微服务是近几年来IT圈内谈论比较多的一个名词,意义也很简单:尽可能细粒度拆分业务程序架构,由多个独立服务组成业务系统。
Docker的容器设计原则:一个容器一个服务,容器之间相互隔离,不妨试想一下,如果容器作为这些独立服务的部署单元,是不是有点恰到好处呢?
- 场景五:弹性伸缩
说到弹性伸缩,通常是集群模式下存在。像AWS AutoScaling,可以自定义资源阈值,SLB自动添加EC2云主机,应对业务访问量突发情况。
当适用Docker技术以后,这种弹性伸缩的单元就是云主机之上的容器了。
容器集群化管理已经有成熟的解决方案,比如:官方的Swarm,谷歌的K8S
由于Docker容器快速启动特性,可以很快速的启动几十个、上百个容器来提供更多并发和资源利用率(如果宿主机资源不够,还需要加主机到集群中)。
docker 好处总结
根据上述应用场景总结下Docker特点:开箱即用,快速部署,可移植性强,环境隔离等。
简化部署流程,提高生产力!
mac安装docker
docker安装nginx
run nginx
1
docker run -d --name nginx -p 8081:80 ngin
访问Nginx
http://localhost:8081
查看log
1
docker logs -f nginx

进入容器
1
docker exec -it nginx bash

停止容器
1
docker stop nginx
查看容器情况
1 | docker ps -a |

- 清理停止容器
1
docker container prune

- 新建目录 在某个目录新建html
1
mkdir html
- 进入目录
1
cd html
- 创建页面
1
echo 'welcome to nginx' > index.html
- 运行命令
把命令行xxx换成html目录下1
docker run --name some-nginx -v /xxx/html:/usr/share/nginx/html -p 8081:80 -d nginx
- 重新访问http://localhost:8081

运行 nginx的总结
docker核心:镜像,容器,仓库
docker 常用命令:
- run— 运行一个镜像
- images –查看本地镜像库
- ps -a –查看本地所有容器状态
- container prune –清理不正常容器
- stop –停止容器
- logs -f 容器id或容器名称 –查看日志
- exec -it 容器id或容器名称 sh –进入容器
- docker info–查看docker 信息
Docker daemon
- docker采用C/S架构,Dcoker daemon作为服务端接受来自客户端请求,并处理这些请求,比如创建容器、管理镜像。
- 为了兼容OCI标准,Docker1.1之后也做了架构调整,Docker容器运行已经不是简单的通过Docker daemon来启动,而是集成了containerd、runc等多个组件。

- Containerd:是一个简单的守护进程,管理shim,向Docker Engine提供接口。使用UnixSocket通信,协议是grpc。
- Shim:管理一个容器
- runC:运行一个容器。是基于OCI标准的一个容器技术实现,是一个可以直接创建和运行容器的工具。runc直接与容器所依赖的cgroups/kernel等进行交互,负责容器所需环境。
docker -镜像(image)
- Docker的流行,很大因素是取决于有数十万计免费的应用镜像,使得用户或者开发者很容器找到可用的镜像。
- 镜像不是一个单一的文件,而是有多层构成。可以理解为镜像是创建容器的模板,一个镜像可以创建N个容器。镜像通常封装了一个应用的基础环境。
- Docker 镜像(Image),就相当于是一个 root 文件系统(不包含linux内核而有精简linux操作系统)
docker–容器(container)
Container中文意思是集装箱,很多人叫容器,其实延续了原理的Linux container,不管叫哪个,含义是一样的。我觉得叫容器比较合适。容器本质上是Linux系统上的一个进程,这个父进程可能会有多个子进程组成,这个一组进程受资源限制,与其他组进程之间隔离。这种运行时的状态成为容器。
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
docker 镜像仓库(images Repository)
- 容器是通过镜像创建的,大量的镜像需要找一个地方存放,这就需要Registry(注册中心)。
- 企业通常自建私有仓库,也可以使用公共仓库,例如:
- Docker Hub 地址:https://hub.docker.com
- Docker官方提供的公共托管Registry,上面有很多现成的镜像,Docker CLI默认就是从这个仓库下载的。
- VMware Harbor 地址:https://github.com/goharbor/harbor VMware Harbor(简称Harbor)项目是由VMware中国研发团队开发的开源容器镜像仓库系统
build java环境(dockerfile)
我们要运行一个spring boot web项目,我们就需要安装java,配置环境变量等等
现在我使用DockerFile 创建有java环境镜像
- 设置阿里云镜像加速

- centos Dockerfile内容build命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18FROM centos
LABEL Author="ywtana<xx@qq.com>"
RUN sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* && \
sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* && \
yum -y update && \
yum install -y java-11-openjdk tzdata && \
yum clean packages && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo Asia/Shanghai > /etc/timezone && \
rm -rf /tmp/* /var/cache/*
RUN groupadd -r test && \
useradd -g test -r test && \
mkdir /test && \
chown -R test:test /test
USER test
WORKDIR /test
RUN ls -al /build成功后1
docker build -t openjdk11_centos .
运行 test用户登录1
docker images
进入容器:1
docker run -u test:test -itd --name openjdk openjdk11_centos
进入容器后输入1
docker exec -it openjdk sh
1
java version


Dockfile描述

DockerFile 指令


docker 命令
上传docker镜像至阿里云

- 打开终端登录阿里云Docker Registry
1
sudo docker login --username=3586*****@163.com registry.cn-hangzhou.aliyuncs.com
- docker tag
1
docker tag nginx registry.cn-hangzhou.aliyuncs.com/test_peter/nginx:latest
- docker push
1
docker push registry.cn-hangzhou.aliyuncs.com/test_peter/nginx:latest
- docker pull
1
docker pull registry.cn-hangzhou.aliyuncs.com/test_peter/nginx:latest

docker命令说明


docker run 参数说明
语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG…]
- -d: 后台运行容器,并返回容器ID;
- -i: 以交互模式运行容器,通常与 -t 同时使用;
- -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
- -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
- –name=”nginx-lb”: 为容器指定一个名称;
- –dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
- -h “mars”: 指定容器的hostname;
- -e username=”ritchie”: 设置环境变量;
- –env-file=[]: 从指定文件读入环境变量;
- –cpuset=”0-2” or –cpuset=”0,1,2”: 绑定容器到指定CPU运行;
- -m :设置容器使用内存最大值;
- –net=”bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
- –volume , -v: 绑定一个卷
docker 镜像与容器联系和存储驱动
- Docker镜像是由多个只读层添加而成,启动容器时,Docker加载值读镜像层并在镜像栈顶部添加一个读写层。
- 如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会在读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写曾中该文件的副本所隐层,这就是我们所说的写时复制,Elasticsearch也是用了写时复制。和这个略有不同。
- 默认情况下,容器不使用任何 volume,此时,容器的数据被保存在容器之内,它只在容器的生命周期内存在,关闭并重启容器,其数据不会受到影响,但是删除Docker容器,数据将会全部丢失。当然,也可以使用 docker commit 命令将它持久化为一个新的镜像
- Docker的数据持久化即使数据不随着container的结束而结束,数据存在于host机器上——要么存在于host的某个指定目录中(使用bind mount),要么使用docker自己管理的volume(/var/lib/docker/volumes下)
- docker run 指定 -v参数
- bind mount例如:
1
docker run --name some-nginx -v /root/html:/usr/share/nginx/html -p 8081:80 -d nginx
- 使用docker volume create my-volume-2 后
1
docker run --name some-nginx -v my-volume-2:/usr/share/nginx/html -p 8081:80 -d nginx
docker网络
Docker自身的4种网络工作方式,和一些自定义网络模式
安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host- host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
- Container:创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。
None:该模式关闭了容器的网络功能。 - Bridge:此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
使用docker network ls 命令列出这些网络

- run创建Docker容器时
- host模式:使用 –net=host 指定。
- none模式:使用 –net=none 指定。
- bridge模式:使用 –net=bridge 指定,默认设置。
- container模式:使用 –net=container:NAME_or_ID 指定。
docker 原理

命名空间(namespaces)是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。
CGroups:让系统中所运行任务(进程)的用户定义组分配资源—比如CPU时间、系统内存、网络带宽
UnionFS:把文件系统上多个目录(分支)内容联合挂载到同一个目录下
namespace
命名空间(namespaces)是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。在日常使用 Linux 或者 macOS 时,我们并没有运行多个完全分离的服务器的需要,但是如果我们在服务器上启动了多个服务,这些服务其实会相互影响的,每一个服务都能看到其他服务的进程,也可以访问宿主机器上的任意文件,这是很多时候我们都不愿意看到的,我们更希望运行在同一台机器上的不同服务能做到完全隔离,就像运行在多台不同的机器上一样。

CGroups
我们通过 Linux 的命名空间为新创建的进程隔离了文件系统、网络并与宿主机器之间的进程相互隔离,但是命名空间并不能够为我们提供物理资源上的隔离,比如 CPU 或者内存,如果在同一台机器上运行了多个对彼此以及宿主机器一无所知的『容器』,这些容器却共同占用了宿主机器的物理资源。

UnionFS
Linux 的命名空间和控制组分别解决了不同资源隔离的问题,前者解决了进程、网络以及文件系统的隔离,后者实现了 CPU、内存等资源的隔离,但是在 Docker 中还有另一个非常重要的问题需要解决 - 也就是镜像。
docker 常用镜像
docker mysql
- 运行mysql 并映射本地数据文件夹 ,映射容器服务的 3306 端口到宿主机的 3306 端口。外部可以直接通过宿主机ip:3306 访问到 的服务;–restart=always参数能够使我们在重启docker时,自动启动相关容器
1
docker run --name mysql --restart=always -p 3306:3306 -v /Users/tanyanwen/Downloads/html/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
- 命令进入mysql容器
1
docker exec -it mysql /bin/bash
- 输入mysql命令 登录mysql
1
mysql -uroot -p

docker redis
- 运行redis 镜像 并映射容器服务的 6379 端口到宿主机的 6379 端口。外部可以直接通过宿主机ip:6379 访问到 Redis 的服务;–restart=always参数能够使我们在重启docker时,自动启动相关容器
1
docker run -itd --restart=always --name redis -p 6379:6379 redis
ubuntu build openjdk11环境
- Dockfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15FROM ubuntu
LABEL Author="peter<xx@qq.com>"
RUN apt update -y && \
apt upgrade -y && \
apt install -y openjdk-11-jre-headless tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo Asia/Shanghai > /etc/timezone && \
rm -rf /tmp/* /var/cache/*
RUN groupadd -r test && \
useradd -g test -r test && \
mkdir /test && \
chown -R test:test /test
USER test
WORKDIR /test
RUN ls -al / - 执行build命令
1
docker build -t openjdk11_ubuntu .
- 运行
1
docker run -u test:test -it --name openjdk openjdk11_ubuntu
- 查看java
1
java -version

alpine build openjdk11环境
- Dockfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16FROM alpine
LABEL Author="peter<xx@qq.com>"
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk update && \
apk upgrade && \
apk add openjdk11 tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo Asia/Shanghai > /etc/timezone && \
rm -rf /tmp/* /var/cache/apk/*
RUN addgroup test && \
adduser -G test test -D && \
mkdir /test && \
chown -R test:test /test
USER test
WORKDIR /test
RUN ls -al / - 执行build命令
1
2
docker build -t openjdk11_alpine . - 运行
1
docker run -u test:test -it --name openjdk openjdk11_alpine
- 查看java
1
java -version

查看docker容器信息
1 | docker inspect 容器id/容器名字 |

docker cache信息
- 查看
1
docker system df
- 删除
本文标题:Docker知识
文章作者:peter.tan
发布时间:2022-08-21
最后更新:2022-09-20
原始链接:https://petertanblog.github.io/2022/08/21/Docker%E7%9F%A5%E8%AF%86/
版权声明:Copyright © 2022 Peter.tan
分享

