Docker入门,看这篇就够了

Docker是怎么出现的

关于Docker的发展史,本文就不作介绍,有兴趣的小伙伴们能够查看这篇文章,挺有意思的。http://www.oschina.net/news/5...css

什么是Docker?

  在Docker以前,咱们确定要先了解Docker是什么。官网的介绍是“Docker is the world’s leading software container platform.”官方给Docker的定位是一个应用容器平台。至于为何要作这个Docker,官网上还有这么一句话"Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications, whether on laptops, data center VMs, or the cloud."这句话用一句很是简单的话去归纳就是"Build once,Run anyWhere".这一点跟Java很像。那么它这样作是要解决现实中什么问题,我列举几个状况。
   1.合做开发的时候,在本机能够跑,别人的电脑跑不起来
   这里咱们拿java Web应用程序举例,咱们一个java Web应用程序涉及不少东西,好比jdk、tomcat、spring等等。当这些其中某一项版本不一致的时候,可能就会致使应用程序跑不起来这种状况。Docker则将程序直接打包成镜像,直接运行在容器中便可。
   2.服务器本身的程序挂了,结果发现是别人程序出了问题把内存吃完了,本身程序由于内存不够就挂了
  这种也是一种比较常见的状况,若是你的程序重要性不是特别高的话,公司基本上不可能让你的程序独享一台服务器的,这时候你的服务器就会跟公司其余人的程序共享一台服务器,因此不可避免地就会受到其余程序的干扰,致使本身的程序出现问题。Docker就很好解决了环境隔离的问题,别人程序不会影响到本身的程序。
  3.公司要弄一个活动,可能会有大量的流量进来,公司须要再多部署几十台服务器
  在没有Docker的状况下,要在几天内部署几十台服务器,这对运维来讲是一件很是折磨人的事,并且每台服务器的环境还不必定同样,就会出现各类问题,最后部署地头皮发麻。用Docker的话,我只须要将程序打包到镜像,你要多少台服务,我就给力跑多少容器,极大地提升了部署效率。前端

Docker与虚拟机的区别

关于Docker与虚拟机的区别,我在网上找到的一张图,很是直观形象地展现出来,话很少说,直接上图。java

图片描述

图片描述

  比较上面两张图,咱们发现虚拟机是携带操做系统,自己很小的应用程序却由于携带了操做系统而变得很是大,很笨重。Docker是不携带操做系统的,因此Docker的应用就很是的轻巧。另外在调用宿主机的CPU、磁盘等等这些资源的时候,拿内存举例,虚拟机是利用Hypervisor去虚拟化内存,整个调用过程是虚拟内存->虚拟物理内存->真正物理内存,可是Docker是利用Docker Engine去调用宿主的的资源,这时候过程是虚拟内存->真正物理内存。node

Docker安装

  Docker的安装很是简单,官网上都给出了具体的安装步骤,都是可视化的安装,三步就搞定了。这里我就不细说了,附上Docker的官网安装教程地址。
Mac:https://docs.docker.com/docke...
Windows:https://docs.docker.com/docke...
linux的话,官网有不一样版本的安装的教程,这里放上ubuntu的安装教程,其余小伙们自行查看。
ubuntu:https://docs.docker.com/engin...linux

Docker三个基本概念

  下面这张图很是的经典,很形象地展现了,什么是容器,什么是镜像,什么是仓库,以及三者之间的联系。
图片描述spring

  接下来咱们来解释一下这张图。如今咱们要造一间厨房,在造以前咱们首先要干的一件事,就是先列举出咱们造厨房须要的东西。咱们可能须要一个通了水电煤的房子以及一些必需的厨房用具诸如锅碗瓢勺、煤气灶、冰箱、水槽等等这些东西。如今咱们知道须要了什么东西以后,咱们就去找这些东西。首先咱们先去京东购买一些厨房用具,这些用具就比如咱们的Docker镜像,咱们厨房的用具到了以后得找个地方把它们放在,不可能随处丢吧,否则后面用的时候就找不到它了,那么咱们Docker镜像也是这样,须要一个Docker仓库去存储这些镜像。如今咱们有了这些厨房用具以后就能够作饭了吗?答案固然是不能,没水没电没火啊!这时候咱们得把厨房用具给装到一个通了水电煤的房子才行,那么Docker镜像也是这样,单纯的Docker镜像是不能用的,它得装到Docker容器中通了水电煤才能使用。等咱们装好了厨房用具以后咱们就能够开始作饭,那么咱们的Docker镜像装到Docker容器以后,咱们应用就能够跑起来了。docker

个人第一个Docker镜像

上面的文章中,咱们了解了一下Docker,接下来咱们学着作一个属于本身的Docker镜像。shell

第一步:从镜像中心下载一个Node镜像

a).去http://hub.daocloud.io/上找到Node镜像地址并执行以下命令
      docker pull daocloud.io/library/node:标签
    b).查看本地库的Docker镜像,是否下载完成
      docker images

结果以下:
图片描述数据库

第二步:写一个app.js

app.js的内容以下,内容很简单,做用也很简单,起一个80端口的服务,页面显示“Hello Docker”。express

var http = require('http');

http.createServer(function (request, response) {

    // 发送 HTTP 头部
    // HTTP 状态值: 200 : OK
    // 内容类型: text/plain
    response.writeHead(200, {'Content-Type': 'text/plain'});

    // 发送响应数据 "Hello World"
    response.end('Hello Docker\n');
}).listen(3000);

// 终端打印以下信息
console.log('Server running at http://127.0.0.1:3000/');

第三步:写一个Dockerfile,用于构建镜像

#依赖的镜像
FROM daocloud.io/library/node:latest
#镜像建立者的信息
MAINTAINER wuming "wuming@maihaoche.com"
#执行mkdir helloDocker建立一个helloDocker文件夹
RUN mkdir helloDocker
#将app.js添加到helloDocker文件夹中
ADD app.js  helloDocker
#容器运行时启动的命令,下面命令等价于 CMD node /helloDocker/app.js
CMD ["node","/helloDocker/app.js"]

第四步:执行命令,构建对象

docker build -t hello-docker .
//-t 用于指定镜像的name:tag,没有指定tag则是latest。
//. 表明Dockerfile 所在的路径,这里是当前目录

结果以下:
图片描述

若是镜像仓库或者标签错了的话,可使用以下命令进行修改

    docker tag IMAGE ID name:tag
   例: docker tag 1786dad83d25 hello-docker:1.0.0

结果以下:
图片描述
这里须要注意的是“docker tag”是新建一个标签用于目标镜像指向源镜像,因此咱们记得删除原来的标签

docker rmi name:tag
例:docker rmi hello-docker:latest

图片描述

舒适提示:当前目录应该有Dockerfile和app.js才可用上面命令构建成功
图片描述

个人第一个Docker容器

docker run  -d -p 8003:3000 IMAGE ID

注意事项:
-p IP:host_port:container_port-p IP::port 来指定容许访问容器的主机上的 IP、接口等,我这里只容许外部8080端口来访问3000端口
-d 就是在后台运行容器,并返回容器ID。有兴趣的小伙伴能够体验一下有-d和没-d的区别

这时咱们输入http://localhost:8003/就能够访问了咱们刚刚启的服务了。
图片描述

另外咱们能够经过docker ps 来查看当前全部启动的容器。
接下来咱们进入容器中看看这个容器到底有什么东西!

docker exec -it <CONTAINER ID 或者 NAMES> /bin/bash

图片描述

进入容器中咱们就看到了刚刚咱们以前在Dockerfile建的helloDocker文件夹,进去以后发现了咱们的app.js.执行exit命令就能够退出容器。

Docker 数据卷的使用

  到这里咱们已经掌握了如何去制做一个镜像以及如何启动一个镜像了,接下来咱们要说点难一点的东西Docker数据卷的使用。首先说一下什么是卷,为何要引入卷这个东西。
  这边咱们拿前端开发来讲,咱们在前端开发中,咱们的js、css以及一些图标等等这些静态资源,这些文件都是能够直接在url输入地址直接访问到的,自己这些东西不会影响项目的运行,说点通俗点就是咱们的这些资源怎么整不会让服务器报500错误.按照咱们前面的方法去作的话,确定之间把这些文件所有打到镜像里面,可是这个方法有个很很差的地方的。就是咱们每次修改他们都须要从新打一次镜像,就感受很繁琐。因而咱们就想,咱们能不能把此次静态资源从镜像中抽离出来,咱们让容器指向这个目录,而后咱们的服务就能够访问这些资源,每次改变完以后咱们就不须要从新打镜像了,这样岂不是很好。正由于如此咱们的数据卷就出来了,用来解决这个问题,那么什么是数据卷呢?咱们用一句话来阐述就是“数据卷是一个可供一个或多个容器使用的特殊目录。”接下来咱们实际操做一把。

数据卷

第一步:咱们创建一个myDocker文件,里面包含两个文件app.js和package.json

app.js的内容以下:

var express = require('express');
var app = express();
//设置public目录为静态目录
app.use(express.static('public'));
//监听3000端口
app.listen(3000);

package.json内容以下(主要目的是安装express,本身能够npm init本身生成一下,没必要抄个人):

{
  "name": "docker",
  "version": "1.0.0",
  "description": "docker test",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.15.3"
  }
}

第二步:在myDocker同级目录下,新建一个public目录,放张图片进去,这里我放了一张美女图片(hhh)。

图片描述

第三步:在myDocker同级目录下新建一个Dockerfile,内容以下:

#设置基础镜像
FROM daocloud.io/library/node:latest
#维护者信息
MAINTAINER wuming wuming@maihaoche.com
#在容器中新建一个myDocker文件中
RUN mkdir myDocker
#将Dockerfile所在目录中myDocker文件夹的内容加到目标容器中的myDocker文件夹中
ADD myDocker  /myDocker
#设置工做目录
WORKDIR /myDocker
#执行安装项目依赖包的命令
RUN npm install
#容器启动时,执行node app.js
CMD node app.js

第四步:构建一个名为my-docker的镜像

当前目录结构为:
myDocker
  ----Dockerfile
  ----myDocker
    ----app.js
    ----package.json
  ----public
构建命令

docker build -t my-docker:latest .

第五步:以挂载方式启动容器

docker run -d -p 8003:3000 -v /Users/wuming/dockerWorkpace/myDocker/public:/myDocker/public  my-docker:latest

这里我将本机的myDocker下的public挂载到容器中的/myDocker/public下,这里咱们能够登入容器中看一下,会发现咱们镜像并无将咱们的public目录打包进去,可是咱们的容器中却有这个public目录。
图片描述

第六步:访问咱们的图片

在游览器地址栏中输入http://localhost:8003/test.jpg即可看见,以下效果:图片描述
你们能够往本身的本机的public丢图片进去,再去访问它试试看,以及看看容器中的public没有动态改变,答案是能够的。

数据卷容器

上面咱们已经实现了数据卷,可是咱们发现加入若是我要起多个容器服务,时间短还能记得这个容器挂载目录,要是时间多了岂不是都忘了,并且每次这样去挂载也挺麻烦的,咱们能不能把咱们已经配好数据卷的容器做为一个数据卷的提供者呢?答案是能够的,这就是咱们要说的数据卷容器,接下来咱们操做一下。
docker run -d -p 8005:3000 --volumes-from NAMES或者CONTAINER ID  my-docker:latest
上面的NAMES或者CONTAINER ID为咱们配好的数据卷的容器。启动完容器以后,咱们能够访问试一下,而且往挂载目录丢点其余图片进去,看看两个容器服务是否是均可以访问到。答案是能够的。

使用网络

外部访问容器

1.映射全部接口地址
-p <端口号(8003)>:<端口号(3000)>

任何ip地址的指定<端口号(8003)>均可以访问到服务(前提是那ip地址对应的主机要起了这个服务)

2.映射到指定地址的指定端口
-p <ip地址(127.0.0.1)><端口号(8003)>:<端口号(3000)>

指定ip地址的<端口号(8003)>均可以访问到服务(前提是那ip地址对应的主机要起了这个服务),好比指定127.0.0.1,只有本机输入127.0.0.1:8003或者localhost:8003能够访问本身的服务,可是其余同一个局域网的手机输入本机的对应局域网的ip地址:8003是访问不到的,小伙们能够拿本身的手机试试。

Docker经常使用命令

1.杀死全部正在运行的容器

docker kill $(docker ps -a -q)

2.删除全部已经中止的容器

docker rm $(docker ps -a -q)

3.删除全部镜像

docker rmi $(docker images -q)

4.关闭容器

docker stop CONTAINER ID或者NAMES

5.从新启动关闭的容器

docker start CONTAINER ID或者NAMES

6.移除本地容器

docker rm CONTAINER ID或者NAMES

7.查看本地容器

docker ps  //查看正在运行的容器
docker ps -a //查看全部容器

8.查看本地镜像

docker images

9.建立镜像

docker build -t name:tag Dockerfile路径

10.修改本地镜像标记

docker tag  IMAGE ID  name:tag 
 docker rmi name:tag

11.删除本地镜像

docker rmi name:tag或者IMAGE ID

12.进入容器

docker exec -it IMAGE ID或者NAMES /bin/bash

13.获取镜像中心的镜像

docker pull name:tag

14.获取容器的端口映射配置

docker port CONTAINER ID或者NAMES

持续更新更新....

Dockerfile命令速查表

FROM 命令

FROM <image>:<tag>

用于设置基础镜像,通常是Dockerfile的第一句。
若是没有指定 tag ,则默认tag是latest。

MAINTAINER

MAINTAINER <name>

用来指定维护者的姓名和联系方式。

RUN

RUN <command> 或 RUN ["executable", "param1", "param2"]

每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。

ADD

ADD <src> <dest>

将 <src> 文件复制到 <dst> 文件:<src> 是相对被构建的源目录的相对路径,能够是文件或目录的路径,也能够是一个远程的文件 url,<dst> 是容器中的绝对路径。

COPY

COPY <src> <dest>

复制本地主机的 <src> (为Dockerfile所在目录的相对路径)到容器中的 <dest>,与ADD指令差很少

ENTRYPOINT

ENTRYPOINT ["executable", "param1", "param2"] :推荐使用的 exec 形式

ENTRYPOINT command param1 param2 :shell 形式

配置容器启动后执行的命令,而且不可被 docker run 提供的参数覆盖。
一个 Dockerfile 中只能有一个 ENTRYPOINT,若是有多个,则最后一个生效。

CMD

CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;
CMD command param1 param2 在 /bin/sh 中执行,提供给须要交互的应用;
CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;

指定启动容器时执行的命令,每一个 Dockerfile 只能有一条 CMD 命令。若是指定了多条命令,只有最后一条会被执行。

若是用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。

WORKDIR

WORKDIR /path/to/workdir

为后续的 RUN、CMD、ENTRYPOINT 指令配置工做目录。

可使用多个 WORKDIR 指令,后续命令若是参数是相对路径,则会基于以前命令指定的路径。例如

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

则最终路径为 /a/b/c 。

EXPOSE

EXPOSE <port> [<port>...]

告诉 Docker 服务端容器暴露的端口号,供互联系统使用。
例如 EXPOSE 8080 3000,开放 8080 和 3000 端口。

ENV

ENV <key> <value>

指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。

VOLUME

VOLUME ["/data"]

建立一个能够从本地主机或其余容器挂载的挂载点,通常用来存放数据库和须要保持的数据等。

USER

USER <UID/Username>

为容器内指定 CMD RUN ENTRYPOINT 命令运行时的用户名或UID。

ONBUILD

ONBUILD [INSTRUCTION]

配置当所建立的镜像做为其它新建立镜像的基础镜像时,所执行的操做指令。
例如,利用Dockerfile建立了一个镜像A,其中Dockerfile中有这么几个命令

ONBUILD RUN mkdir test
ONBUILD ADD app.js /test/app.js

那么镜像B基于镜像A去构建的时候,默认会在最后加上这两行命令

FROM 镜像A
 RUN mkdir test
 ADD app.js /test/app.js