大纲
- docker是什么?
- 谁在使用Docker?
- docker与虚拟机
- docker的使用
- 安装
- Docker Machine 与 Docker Desktop for Mac
- 使用
- docker如何制作镜像?
- 运行一个docker容器
- 安装
- docker的架构
前言
准备环境是一件高成本、费时、手工且十分不优雅的事情。
1. docker是什么?
Docker 是一个允许用户“在任何地方构建、分发及运行任何应用”的平台(引擎)。
一个架子,可以用来放很多抽屉。这样想象一下。
Docker提供了一种在容器中运行安全隔离的应用程序的方法,它与所有依赖项和库打包在一起。
Docker 是一个开源的应用容器引擎[1],让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制[2],相互之间不会有任何接口。
1 - 应用容器引擎
2 - 沙箱机制 - 网络编程虚拟执行环境
Sandboxie(又叫沙箱、沙盘)即是一个虚拟系统程序,允许你在沙盘环境中运行浏览器或其他程序,因此运行所产生的变化可以随后删除。它创造了一个类似沙盒的独立作业环境,在其内部运行的程序并不能对硬盘产生永久性的影响。其为一个独立的虚拟环境,可以用来测试不受信任的应用程序或上网行为。
简单来讲指的是虚拟环境、系统和真是环境相同的,主要的功能就是研究危险东西,比如一些随时可能导致系统崩溃的程序、病毒等,咱们常见的虚拟机就是一个沙箱。
一个完整的Docker有以下几个部分组成:
- DockerClient客户端
- Docker Daemon守护进程
- Docker Image镜像
- DockerContainer容器 [docker教程]
特点:
- 上手快
用户只需要几分钟,就可以把自己的程序“Docker 化”。Docker 依赖于“写时复制” (copy-on-write)模型,使修改应用程序也非常迅速,可以说达到“随心所致,代码即改” 的境界。
随后,就可以创建容器来运行应用程序了。大多数 Docker 容器只需要不到 1 秒中即可 启动。由于去除了管理程序的开销,Docker 容器拥有很高的性能,同时同一台宿主机中也 可以运行更多的容器,使用户尽可能的充分利用系统资源。
- 职责的逻辑分类
使用 Docker,开发人员只需要关心容器中运行的应用程序,而运维人员只需要关心如 何管理容器。Docker 设计的目的就是要加强开发人员写代码的开发环境与应用程序要部署 的生产环境一致性。从而降低那种“开发时一切正常,肯定是运维的问题(测试环境都是正 常的,上线后出了问题就归结为肯定是运维的问题)”
- 快速高效的开发生命周期
Docker 的目标之一就是缩短代码从开发、测试到部署、上线运行的周期,让你的应用 程序具备可移植性,易于构建,并易于协作。(通俗一点说,Docker 就像一个盒子,里面 可以装很多物件,如果需要这些物件的可以直接将该大盒子拿走,而不需要从该盒子中一件 件的取。)
- 鼓励使用面向服务的架构
Docker 还鼓励面向服务的体系结构和微服务架构。Docker 推荐单个容器只运行一个应 用程序或进程,这样就形成了一个分布式的应用程序模型,在这种模型下,应用程序或者服 务都可以表示为一系列内部互联的容器,从而使分布式部署应用程序,扩展或调试应用程序 都变得非常简单,同时也提高了程序的内省性。(当然,可以在一个容器中运行多个应用程序)
指明你需要的资源,调用外面的资源,也可以有内部分离。
也可以有个公共的,然后其他的指向过来。
2. 谁在使用Docker?
世界领先的公司和数百万开发人员使用Docker来部署和管理应用程序,包括:
3. docker与虚拟机
虚拟机
所谓虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能、并可以运行在一个完全隔离环境中的完整计算机系统。虚拟机就是相对于传统计算机而言的计算机概念,一个非实体的计算机,但具有所有传统计算机的功能。
下面我们来分析一下,docker与虚拟机。看看他们各自是怎么实现的?
虚拟机和Docker都能够给一台宿主机上的应用提供隔离的运行环境。区别是什么呢?
从上图右边虚拟机架构图能看出,虚拟机里在宿主操作系统和物理硬件之间多了一个中间层:Hypervisor。
Hypervisor是一种运行在物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享一套基础物理硬件,事实上成为虚拟环境中的“元”操作系统,Hypervisor可以协调访问服务器上的所有物理设备和虚拟机,也称为虚拟机监视器(Virtual Machine Monitor)。Hypervisor是所有虚拟化技术的核心。当服务器启动并执行Hypervisor时,它会给每一台虚拟机分配适量的内存、CPU、网络和磁盘,并加载所有虚拟机的客户操作系统,每台虚拟机有自己的虚拟操作系统和存储空间,因此需要消耗宿主机大量的物理资源,同时也需要花费一定时间来启动。
而上图左边,Docker直接运行在宿主机的操作系统上,没有Hypervisor这个中间层。Docker实际上就是运行于操作系统上的普通进程,通过Linux Primitives实现的彼此隔离,但是共享同一个操作系统内核。
正因为这种共享性,使得Docker的资源占用远小于虚拟机,而且启动速度也远远快于虚拟机。
接下来,我们可以用一张图形象的看下使用上的一些区别:
Size:
1.Mac上启动Windows虚拟机所占内存:
Startup:
- 虚拟机:Windows上启动ubuntu要2分钟左右,而Mac上启动Windows也要将近1分钟。
- docker只需要2s。
4. docker的使用
上面我们介绍了许多原理性的知识点,所有的原理都是为了实现,那么下面我们来上手实践一下,看是不是真的像原理以及和虚拟机的对比分析那样呢?
1. 安装
-
双击Docker.dmg打开安装程序,然后将Moby the whale拖到Applications文件夹。
双击Docker.appApplications文件夹以启动Docker。(在下面的示例中,“应用程序”文件夹处于“网格”视图模式。)
Docker.app启动后,系统会提示您使用系统密码进行授权。需要特权访问才能安装网络组件和Docker应用程序的链接。
顶部状态栏中的鲸鱼表示Docker正在运行,并且可以从终端访问。
状态栏中的whale()以关闭此弹出窗口。
- 单击whale以获取首选项和其他选项。
- 选择关于Docker以验证您是否拥有最新版本。
这样我们就启动并运行了Docker Desktop for Mac。
- 可以在控制台使用
docker -v
进行版本查看。
2. 使用
1. Check versions
$ $ docker --version
Docker version 19.03.1, build 74b1e89
$ docker-compose --version
docker-compose version 1.24.1, build 4667896b
$ docker-machine --version
docker-machine version 0.16.1, build cce350d7
2. Explore the application
我们运行docker run hello-world
:
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete
Digest: sha256:ca0eeb6fb05351dfc8759c20733c91def84cb8007aa89a5bf606bc8b315b9fc7
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
3. 下载mongo镜像并启动一个容器(mongo的容器)
$ docker run --name mongo -d -p 27017:27017 mongo
Unable to find image 'mongo:latest' locally
latest: Pulling from library/mongo
...
306b575ddfff: Pull complete
ee1475733b36: Pull complete
Digest: sha256:ec1fbbb3f75fdee7c3433ce2d5b8200e7c9916c57902023777bec5754da5e525
Status: Downloaded newer image for mongo:latest
94678bd126546197658d6fb8a4a78e264c12a9227187b55c5d2a0de74ce34ac2
-d 后台执行
-p 端口映射出来,让宿主机可以访问到
4. Docker子命令
命令 | 目的 |
---|---|
docker build | 构建一个Docker镜像 |
docker run | 以容器形式运行一个Docker镜像 |
docker commit | 将一个Docker容器作为一个镜像提交 |
docker tag | 给一个Docker镜像打标签 |
docker start [name|container id] | 启动一个被暂停的容器 |
docker stop [name| container id] | 停止一个已经启动的容器 |
docker rm name/id | 可以删除已经停止的容器 |
docker rm -f name/id | 可以删除正在运行的容器。 |
docker images | 查看镜像 |
docker rmi id | 删除镜像 |
docker push xxx | 发布镜像 |
docker pull xxx | 下载镜像 |
3. 制作镜像
我们先来说一下镜像和容器。
一个简单的理解就是将镜像看做类而将容器看做对象。对象是类的具体实例,同样,容器是镜像的实例。用户可以从单个镜像创建多个容器,就像对象一样,他们之间全都是相互隔离的。不论用户在对象内修改了什么,都不会影响类的定义 -- 它们从根本上就是不同的东西。
1. 创建镜像
创建镜像有4种标准的方式。
- 手工
- Dockerfile
- Dockerfile以及配置管理工具(CM)
- 从头创建镜像并导入一组文件
今天咱们主要介绍第二种:Dockerfile。
# 定义基础镜像
FROM node:12.8.1-stretch
# 声明维护人员
MAINTAINER [email protected]
# 克隆代码
RUN git clone https://github.com/springHyc/node-hello-world.git
# 移动到新的克隆目录
WORKDIR /node-hello-world/blog
# 运行node包管理器的安装命令(npm)
RUN npm install > /dev/null
# 指定从都构建的镜像启动的容器需要监听的端口
EXPOSE 4321
# 指定在启动时需要运行的命令
CMD ["node", "index.js"]
执行创建镜像的命令:
$ docker build -t blog-image:0.0.1 .
Sending build context to Docker daemon 2.048kB
Step 1/7 : FROM node:12.8.1-stretch
12.8.1-stretch: Pulling from library/node
9cc2ad81d40d: Pull complete
e6cb98e32a52: Pull complete
ae1b8d879bad: Pull complete
42cfa3699b05: Pull complete
053cac798c4e: Downloading [===========> ] 49.24MB/215.1MB
e11ff976ff71: Download complete
224731f6b161: Downloading [=============================> ] 13.04MB/21.88MB
56ed10abd115: Download complete
053cac798c4e: Downloading [============> ] 55.66MB/215.1MB
053cac798c4e: Pull complete
e11ff976ff71: Pull complete
224731f6b161: Pull complete
56ed10abd115: Pull complete
f93be52154ee: Pull complete
Digest: sha256:2eb5b7ee06215cda1c697c178978c51367b78ee3992a058f37b73616521fc104
Status: Downloaded newer image for node:12.8.1-stretch
---> e3e4ac3015dd
Step 2/7 : MAINTAINER [email protected]
---> Running in d92c67510758
Removing intermediate container d92c67510758
---> a45bb1abc41a
Step 3/7 : RUN git clone https://github.com/springHyc/node-hello-world.git
---> Running in c9d2ff81c844
Cloning into 'node-hello-world'...
Removing intermediate container c9d2ff81c844
---> 4fe592793e15
Step 4/7 : WORKDIR /node-hello-world/blog
---> Running in 6d316304889d
Removing intermediate container 6d316304889d
---> 0cbd2e8a3354
Step 5/7 : RUN npm install > /dev/null
---> Running in acd2a325eee2
npm WARN [email protected] No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
Removing intermediate container acd2a325eee2
---> 09c6454af527
Step 6/7 : EXPOSE 4321
---> Running in af6b52b86a06
Removing intermediate container af6b52b86a06
---> 84f3511639f6
Step 7/7 : CMD ["node", "index.js"]
---> Running in 02a93459f5a6
Removing intermediate container 02a93459f5a6
---> a5cab15f2dcc
Successfully built a5cab15f2dcc
Successfully tagged blog-image:0.0.1
$ docker ps -a
// 查看镜像
2. 运行一个Docker容器
$ docker run -p 4321:4321 --name blog1 blog-image
Unable to find image 'blog-image:latest' locally
docker: Error response from daemon: pull access denied for blog-image, repository does not exist or may require 'docker login': denied: requested access to the resource is denied.
See 'docker run --help'.
BR-IT-A00354:docker-blog bairong$ docker run -p 4321:4321 --name blog1 blog-image:0.0.1
the server/replset/mongos/db options are deprecated, all their options are supported at the top level of the options object [poolSize,ssl,sslValidate,sslCA,sslCert,sslKey,sslPass,sslCRL,autoReconnect,noDelay,keepAlive,keepAliveInitialDelay,connectTimeoutMS,family,socketTimeoutMS,reconnectTries,reconnectInterval,ha,haInterval,replicaSet,secondaryAcceptableLatencyMS,acceptableLatencyMS,connectWithNoPrimary,authSource,w,wtimeout,j,forceServerObjectId,serializeFunctions,ignoreUndefined,raw,bufferMaxEntries,readPreference,pkFactory,promiseLibrary,readConcern,maxStalenessSeconds,loggerLevel,logger,promoteValues,promoteBuffers,promoteLongs,domainsEnabled,checkServerIdentity,validateOptions,appname,auth,user,password,authMechanism,compression,fsync,readPreferenceTags,numberOfRetries,auto_reconnect,minSize,monitorCommands,retryWrites,useNewUrlParser,useUnifiedTopology,serverSelectionTimeoutMS,useRecoveryToken]
Wed, 21 Aug 2019 07:01:09 GMT body-parser deprecated bodyParser: use individual json/urlencoded middlewares at index.js:31:31
Wed, 21 Aug 2019 07:01:09 GMT body-parser deprecated undefined extended: provide extended option at node_modules/body-parser/index.js:105:29
Express started on http://localhost:4321;press Ctrl - C to terminate.
可以打开[http://localhost:43210/api](172.30.5.101:43210/api)
进行查看
3. 一个复杂的Dockerfile
上面我们介绍了一个简单项目的制作镜像以及运行一个docker 容器。
下面我们来看一个比较复杂的Dockerfile。它里面包含了,一个简单前端(react)项目,一个后端服务(node)以及后端连接所需要的DB(mongo)。
FROM ubuntu:18.04
MAINTAINER [email protected]
# apt 更新软件列表
RUN apt update
# 安装依赖
RUN apt install nginx git curl mongodb -y
RUN curl -sL https://deb.nodesource.com/setup_9.x | bash - && apt-get install nodejs -y
# 前端打包
RUN git clone -b master https://github.com/springHyc/hehe-blog.git
WORKDIR /hehe-blog
RUN npm install
RUN npm run build
RUN mv build /web
# 后端安装依赖
WORKDIR /
RUN git clone -b localdb https://github.com/springHyc/node-hello-world.git
WORKDIR /node-hello-world/blog
RUN npm install
# 添加nginx配置文件
ADD ./blog.conf /etc/nginx/conf.d/
# 添加启动文件
WORKDIR /
ADD ./run.sh /
#
EXPOSE 9998
#
CMD ["bash", "run.sh"]
这是生成的镜像:
这是运行的容器:
我们可以打开172.30.5.101:30001
进行查看。
5. docker的架构
DockerHub 是有Dokcer公司运营的一个公共注册中心。
咱们可以将自己的镜像推上去,也可以从上面选择我们需要的镜像。
docker push
命令可以将某一个镜像发布到官方网站。
Docker注册中心早就的是与GitHub相似的社交编码文化。
参考
- docker官网
- 视频学习