Docker 是一个开源的应用容器引擎,基于Go 语言并听从 Apache2.0 协议开源。
Docker 可让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,而后发布到任何流行的 Linux 机器上,也能够实现虚拟化。html
这里可移植指的是,能够直接将镜像保存为镜像压缩文件,而后能够将这个镜像压缩文件发送到任何一台机器上从新加载成镜像,而后根据该镜像建立容器便可完成移植。vue
容器是彻底使用沙箱机制,相互之间不会有任何接口(相似 iPhone 的 app),更重要的是容器性能开销极低。node
沙箱是一个虚拟系统程序,沙箱提供的环境相对于每个运行的程序都是独立的,并且不会对现有的系统产生影响。ios
沙箱具备很是良好的独立性、隔离性,因此可以搭建一些具备高风险的软件进行测试。好比,你能够在沙箱里面运行一个病毒程序,也是安全的。nginx
Docker容器应用场景:web
Docker容器的优势:redis
镜像至关因而一个root文件系统,能够理解成一个软件安装包。好比nginx镜像,有了nginx镜像文件,就至关于有了nginx软件安装包,咱们就能够对nginx进行安装运行了。docker
容器至关因而一个镜像运行的环境,能够理解为咱们的电脑操做系统。因此咱们能够将咱们的镜像文件安装到咱们的容器中,当咱们启动容器的时候,能够经过指定CMD在容器运行后所要执行的命令,来运行咱们的镜像。数据库
仓库,用于保存镜像的一个仓库,有本地镜像仓库和官方的远程镜像仓库(Docker Hub),相似于代码提交的仓库,咱们能够从远程镜像仓库下载镜像到本地,也能够将本地建立的镜像推送到远程仓库中。express
① 镜像的基础操做
咱们要建立容器必需要基于镜像。当咱们安装好Docker以后,咱们就能够直接在终端中经过docker命令从远程镜像仓库(Docker Hub)进行镜像的下载,下载无需登陆便可Docker 帐号,只有将本地镜像推送到Docker Hub才须要登陆。
docker search image_name
// 搜索nginx镜像资源 docker search nginx
// 搜索官方发布的ngnix镜像 docker search --filter "is-official=true" nginx // 搜索自动化发布的镜像 docker search --filter "is-automated=true" nginx // 搜索星星数量在2000以上的镜像 docker search --filter "stars=2000" nginx
// 从远程Docker Hub中下载nginx镜像 docker pull nginx
// 查看本地仓库中有哪些镜像 docker images
// 从本地仓库中删除nginx镜像 docker rmi nginx // 从本地仓库中强制删除vuenginx镜像 docker rmi -f vuenginx
// 将docker中的vuenginx镜像导出到宿主机上 docker save -o vuenginx.tar vuenginx
-o即--output,指定保存后的镜像名称,以后的参数为docker中要被导出的镜像名
// 加载宿主主机当前目录下的images目录下的名为vuenginx的镜像压缩包 docker load -i ./images/vuenginx.tar
须要注意的是,压缩包的名称并不会影响加载后镜像的名称,即镜像保存的时候是基于哪一个镜像,加载后显示的也是哪一个镜像。
// 基于宿主机上./images/vuenginx.tar镜像压缩包导入到docker中并命名为test docker import ./images/vuenginx.tar test
注意,镜像名称必须全小写。
两者的区别:
docker import:丢弃了全部的历史记录和元数据信息,仅保存容器当时的快照状态。在导入的时候能够从新制定标签等元数据信息。
docker load:将保存完整记录,体积较大。
② 容器的基础操做
有了镜像,咱们就能够基于镜像来建立、运行容器了。
// 基于nginx镜像建立名为nginxContainer容器 docker create --name nginxContainer nginx docker create --name "nginxContainer" nginx docker create --name=nginxContainer nginx docker create --name="nginxContainer" nginx
--name指定容器名称的时候,以上四种方式均可以。经过created命令建立的容器会处于Created状态,同名的容器不能重复建立。
// 从新启动、运行指定的容器 docker restart nginxContainer
运行的容器会处于Up状态。
docker run -itd --name=container_name image_name
-i 表示以交互模式运行容器,一般与-t同时使用;
-t 表示为容器从新分配一个伪输入终端,一般与-i同时使用;
-d 表示后台运行容器,并返回容器ID
--name 为容器指定名称,同create命令,若是没有指定名称,那么docker为建立的容器自动生成一个名称。
// 基于nginx容器建立并运行容器 docker run nginx docker run -i nginx docker run -t nginx docker run -it nginx
以上四个命令执行后终端会停住没法输入,由于容器在前台运行,而且因为没有经过--name指定,因此建立的容器名由docker自动生成,结束终端以前,建立的容器会一直处于运行状态,结束终端后容器会当即进行中止状态。
// 基于nginx容器建立并运行名为nginxContainer的容器 docker run -itd --name nginxContainer nginx
以上命令执行后,终端会当即返回容器的id,而且容器在后台运行,此时终端能够继续输入,而且容器也处于运行状态。
在run容器的时候,还能够传递一个COMMAND,即在容器运行起来以后执行指定的命令,而且这个命令会影响建立的容器的状态。
若是这个命令是能够持续运行的,那么容器也能够进入到运行状态。
若是这个命令是执行完成后就结束的,那么容器也会随着命令的结束而进入中止状态。
也就是说,若是想让建立的容器处于一直运行状态,那么咱们必须在容器启动后执行一个可持续运行的命令。如:
# 容器基于nginx镜像建立并启动而且容器启动后执行 echo "hello docker"命令 docker run -itd --name test nginx echo "hello docker"
因为容器启动后执行的命令是执行完成后就结束的命令,因此建立的test容器也随之进入中止状态。
# 容器基于nginx镜像建立并启动而且容器启动后执行 sleep 10 docker run -itd --name test nginx sleep 10
因为容器启动后执行的命令是能够持续执行10秒的命令,因此建立的test容器会运行10秒后再进入中止状态。
// 查看运行中的容器信息 docker ps // 查看全部容器信息包括已经中止运行的 docker ps -a // 查看运行中的容器信息 docker container list // 查看全部容器信息包括已经中止运行的 docker container list -a
根据命令输出结果,咱们能够看到容器id只显示了一部分,而咱们的容器id的值实际上是一个64位的字符串,若是咱们想要完整的显示出来,能够加上--no-trunc
参数,如:
# 查看容器各字段详细信息 docker ps -a --no-trunc
// 中止正在运行的名为nginxContainer的容器 docker stop nginxContainer
// 从新运行的名为nginxContainer的容器 docker restart nginxContainer
// 删除已经中止运行的名为nginxContainer的容器,若是该容器还在运行,必须先stop掉,再删 docker rm nginxContainer
// 进入容器的终端界面,其实就是在容器中执行了bash命令 docker exec -it nginxContainer bash
须要注意的是,必须带上-i和-t,-t只能进入到容器的终端界面,但没法进行命令交互,-i只可以进行命令交互,可是没有终端界面,不是很好用,因此-it才能进行正常命令交互。
// 提交nginxContainer容器上的修改,而且将提交而产生的镜像命名为new_nginxontainer docker commit -m "create a new image" nginxContainer new_nginxontainer
# 将vueApp这个容器进行导出而且保存为vueApp.tar镜像压缩包 docker export vueApp > vueApp.tar
# 将vueApp.tar镜像压缩包导入并保存为镜像,名字为vueappimage docker import vueApp.tar vueappimage # 同一个镜像能够被导入保存为镜像屡次 docker import vueApp.tar vueappimage2
③ 容器的进阶操做
容器的进阶操做,主要是指docker容器和宿主机之间端口、文件的绑定,实现宿主机中修改可以当即同步到docker容器中。
// 将宿主机的8080端口与docker的80端口进行映射 docker run -itd --name nginxContainer -p 8080:80 nginx
此时浏览器地址栏中输入http://localhost:8080/,请求就会被转发到docker的80端口上,就能查看到nginx提供的默认首页了
// 将宿主主机下指定目录与docker容器目录进行关联 docker run -itd --name vueApp -p 8080:80 -v /**/**/test-docker/dist:/usr/share/nginx/html/ vuenginx
须要注意是,本地宿主主机目录必须是绝对路径,而且若是宿主主机上该目录文件发生变化,那么须要执行restart命令重启容器才会生效。
此时本地宿主主机中的目录和容器中的目录就被关联起来了,关联目录下本地文件一旦被修改,用户再次访问页面的时候就会显示修改过的页面了。
// 将容器中的/etc/nginx/conf.d/default.conf文件拷贝到宿主主机的/**/**/target_dir/目录中 docker cp nginxContainer:/etc/nginx/conf.d/default.conf /**/**/target_dir/ // 将宿主主机中的/www/index.html 拷贝到容器的/usr/share/nginx/html/ 目录下 docker cp /www/index.html nginxContainer:/usr/share/nginx/html/
Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
Dockerfile文件结构通常分为四部分,基础镜像信息、维护者信息 镜像操做指令和容器启动时执行的指令,dockerfile文件中能够经过#号进行注释。
指令详解
# 以nginx镜像为基础进行构建 FROM nginx
# lihb维护该dockerfile文件 MAINTAINER lihb
# 执行命令安装项目所需依赖 RUN npm install
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
上面的仅表示换行,若是命令短的话,其实能够不须要换行,可是换行必须加上斜杠。
# 不换行写法 FROM nginx RUN echo "test" && pwd && ls
# dockfile文件所在目录下的dist目录下的全部文件添加到docker容器中指定目录下 COPY dist/ /usr/share/nginx/html/ COPY nginx/default.conf /etc/nginx/conf.d/default.conf
COPY指令中,宿主主机上的目录必须是相对于构建时所用的dockerfile所在的目录。
相同功能下,建议使用COPY。
# 执行命令安装项目所需依赖 RUN npm install # 执行npm start脚本 CMD ["npm", "start"]
ENTRYPOINT ["nginx", "-g", "daemon off;"]
ENV PATH /usr/local/nginx/sbin:$PATH # 后续的指令中能够经过 $NODE_VERSION 引用 ENV NODE_VERSION 7.2.0
# 声明容器可使用80和443端口 EXPOSE 80 443
# 容器运行时,会建立一个/foo目录 VOLUME /foo
# 至关于执行了cd /usr/src/docker-server WORKDIR /usr/src/docker-server
ARG NGINX_VERSION=1.15.0
经过dockerfile文件构建镜像
能够经过docker build 命令进行镜像的构建,-f指定dockerfile文件的路径,-t指定构建好的镜像名称,最后加一个.
// 千万不要少了最后面的那个点 docker build -f /path/to/dockerfile -t image_name .
dockerfile文件的名称或后缀能够任意,只要里面的指令正确就行。若是没有经过-f指定dockerfile文件的路径,那么默认会找当前终端所在目录下的dockerfile文件,没有则构建失败。
① 经过Vue CLI建立Vue项目
这一步比较简单,直接经过vue create 命令建立便可,如:
# 建立一个名称为test-docker的项目 vue create test-docker # 进入到test-docker项目根目录 cd test-docker # 构建vue项目 npm run build
执行完npm run build
后,会在项目根目录下建立一个dist目录,里面存放的就是vue项目打包后的结果,用于生产发布。咱们只须要将dist目录中的内容部署到静态资源站点就能够直接访问到该项目了。下面咱们将以nginx服务器为例,在docker中建立一个nginx的容器来运行咱们的nginx服务器,同时将dist目录中的内容放到nginx服务器的静态资源站点下。
② 建立包含dist目录中内容的nginx镜像
这里咱们以官方的nginx镜像为基础,同时将dist目录中的内容拷贝到nginx静态资源站点下,并构建出一个新的镜像,而后再根据这个新的镜像去建立容器,那么建立好的容器中就会带上dist目录下的内容。固然也在容器建立好以后再将dist中的目录拷贝进去也是能够的。
# 以官方的nginx镜像为基础进行构建 FROM nginx # 将当前dockerfile所在目录下的dist目录的内容拷贝到容器的/usr/share/nginx/html/下 COPY dist/ /usr/share/nginx/html/
根据该dockerfile构建出带有dist目录内容的nginx镜像。
# 进入到vue项目根目录 cd /path/to/vue项目根目录 # 构建镜像,镜像名为vuenginx docker build -t vuenginx .
当咱们在vue项目根目录下执行docker build命令的时候,docker会自动在当前目录下寻找dockerfile文件,而后根据dockerfile文件中的指令进行镜像的构建,构建出的镜像名为 -t指定的名称,须要注意的是最后的点号不能少。
打开终端输入如下命令检查镜像是否建立成功,如:
# 打开终端直接输入如下命令 docker images | grep "vuenginx"
③ 建立并运行vueApp容器
建立好镜像以后,咱们就能够基于该镜像建立并运行容器了,如:
# 基于vuenginx运行容器 docker run -itd --name vueApp -p 8080:80 vuenginx # 查看容器信息 docker ps -a
运行容器而且将本地主机的8080端口与容器的80端口绑定,当咱们在本地主机上访问8080端口的时候,请求就会被转发到容器的80端口上,从而被容器中的nginx服务器处理。
此时咱们在本地主机浏览器上访问http://localhost:8080/,便可看到咱们的vue项目首页了,说明咱们已经成功在docker容器中部署了一个静态资源服务器。为了可以让咱们的vueApp可以发起异步请求数据,咱们还须要在docker中建立node服务器容器,提供web服务器功能。
④ 新建node应用做为vue应用的web服务器
新建一个node项目,并在node项目根目录下建立一个index.js做为node应用启动入口文件,以下:
# 建立docker-server目录 mkdir docker-server # 初始化package.json文件 npm init --yes # 新建index.js文件
index.js内容以下
const express = require("express"); const app = express(); app.get("/docker", (req, res, next) => { res.send("hello, welcome to docker web server for vueApp."); }); app.listen(3000);
package.json内容以下:
{ "name": "docker-server", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1" } }
⑤ 建立nodeserver镜像
这里咱们以官方的node镜像为基础,同时将node应用根目录下的内容拷贝到镜像中,并安装项目依赖,并构建出一个新的镜像,而后再根据这个新的镜像去建立容器,那么建立好的容器中就会带上node应用的源码了。
# 构建node镜像 FROM node # 找一个目录存放咱们的server代码, 至关于执行了cd /usr/src/docker-server WORKDIR /usr/src/docker-server # 复制当前目录内容 到容器中指定的应用根目录下 COPY . . # 执行命令安装项目所需依赖 RUN npm install # 让容器可使用3000端口 EXPOSE 3000 # 容器启动后执行npm start脚本 CMD ["npm", "start"]
这里node_modules和dockerfile文件中的东西就不须要拷贝到镜像里去了,咱们直接在镜像里面安装便可,能够添加一个.dockerignore文件进行忽略,如:
# .dockerignore文件内容 node_modules npm-debug.log dockerfile Dockerfile
根据该dockerfile构建出带有node应用node镜像。
# 进入到docker-server项目根目录 cd /path/to/docker-server项目根目录 # 构建镜像,镜像名为nodeserver docker build -t nodeserver .
⑥ 建立并运行vueServer容器
# 基于nodeserver建立并运行容器 docker run -itd --name vueServer -p 8888:3000 nodeserver
这里将本地主机的8888端口与docker容器的3000端口进行了映射。
容器运行后,在本地主机访问http://localhost:8888/test,检测docker下的node服务器是否部署成功。
说明docker下的node服务器已经部署成功了,接下来咱们须要修改vue项目,让其访问这个node服务器。
⑦ 修改Vue项目
在HelloWorld.vue组件的created生命周期中添加一个向服务器异步获取数据的接口,如:
# 安装axios并引入 import axios from "axios" created() { axios.get("/api/docker").then((res) => { this.msg = res.data; }); }
如今咱们在本地主机访问vue项目的时候,会发起http://localhost:8080/api/docker的请求,请求会被转发到docker容器的80端口,即http://localhost/api/docker,可是咱们docker中的服务器是3000端口,因此须要进行跨域,因此咱们还要修改nginx的配置文件添加代理。
因为vueApp和vueServer是在两个不一样的容器中,就至关因而在两台不一样的电脑上,因此咱们不能再使用localhost进行请求转发了,必须找到vueServer的ip地址,有两种方式,如:
可知其ip地址为172.17.0.2
在vue项目根目录下新建一个nginx目录,而后新建一个default.conf,配置文件内容以下:
server { listen 80; server_name localhost; access_log /var/log/nginx/host.access.log main; error_log /var/log/nginx/error.log error; location / { root /usr/share/nginx/html; index index.html index.htm; } location /api/ { rewrite /api/(.*) /$1 break; proxy_pass http://172.17.0.2:3000; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
此时咱们在本地主机修改后,重启容器,发现修改并无应用咱们刚刚的修改,咱们还得按上面的步骤从新建立镜像和容器,这样显然是很是麻烦,咱们能够将本地主机的文件或目录与docker容器中的文件或目录进行挂载,这样当本地主机修改后,容器重启便可应用本地主机的修改。
# 中止并删除以前的vueApp容器 docker stop vueApp docker rm vueApp # 从新建立运行容器并进行文件挂载绑定 docker run -itd --name vueApp -p 8080:80 \ --mount type=bind,source=/path/to/test-docker/dist,target=/usr/share/nginx/html \ --mount type=bind,source=/path/to/test-docker/nginx,target=/etc/nginx/conf.d \ nginx
固然咱们也能够经过-v进行文件的挂载,如:
# 中止并删除以前的vueServer容器 docker stop vueServer docker rm vueServer # 从新建立运行容器并进行文件挂载绑定 docker run -itd --name vueServer -p 8888:3000 \ -v /Users/banma-798/Documents/learn/docker-server:/usr/src/docker-server nodeserver
此时再次访问http://localhost:8080,页面以下显示,表示跨域请求成功。
⑧ 配置负载均衡
为了可以让后端服务器可以处理更多请求,一般咱们会配置多台服务器,以保证后端服务器的稳定,提升吞吐量和减小延迟,最大化资源利用率。因此咱们能够再建立一个vueServer容器,如:
# 再次建立并运行一个node服务器,容器名为vueServer2 docker run -itd --name vueServer2 -p 9999:3000 \ -v /Users/banma-798/Documents/learn/docker-server:/usr/src/docker-server nodeserver
此时咱们在本地主机上访问http://localhost:9999/docker,若是请求成功表示第二台服务器启动成功。
查看新建的vueServer2的ip地址为172.17.0.4
修改配置文件,以下:
upstream backend{ server 172.17.0.4:3000; server 172.17.0.2:3000 } location /api/ { rewrite /api/(.*) /$1 break; proxy_pass backend; }