《前端运维》三、Docker--2其他
一、制作DockerFile
docker的镜像类似于用一层一层的文件组成。inspect命令可以查看镜像或容器的的信息,其中Layers就是镜像的层文件,只读不能修改,基于镜像创建的容器会共享这些层。下面我们先来学习一下dockerFile中的一些命令:
- form,构建的新镜像是基于哪个镜像
- form centos:6
- maintainer,镜像维护者姓名或邮箱地址。
- maintainer zaking。
- run,构建镜像时运行的shell命令。
- RUN yum install httpd
- cmd,设置容器启动后默认执行的命令及其参数,但cmd能够被docker run后面的命令及参数替换。cmd给出的是一个容器的默认的可执行体。也就是容器启动以后,默认的执行的命令。重点就是这个"默认"。意味着,如果
docker run
没有指定任何的执行命令或者dockerfile
里面也没有entrypoint
,那么,就会使用cmd指定的默认的执行命令执行。同时也从侧面说明了entrypoint
的含义,它才是真正的容器启动以后要执行命令。- CMD /usr/sbin/sshd -D
- CMD /usr/sbin/sshd -D
- expose,声明容器运行的端口。
- EXPOSE 80 443
- env,设置容器内的环境变量。
- ENV MYSQL_ROOT_PASSWORD 123456
- add,拷贝文件或目录到镜像中,如果是URL或者压缩包会自动下载和解压。
- ADD ,ADD https://xxx.com/html.tar.gz /var/www.html, ADD html.tar.gz /var/www/html
- copy,拷贝文件或目录到镜像。
- COPY ./start.sh /start.sh
- entrypoint,配置容器启动时运行的命令。
- ENTRYPOINT /bin/bash -c '/start.sh'
- volume,指定容器挂载点到宿主自动生成的目录或其它容器。
- VOLUME ["/var/lib/mysql"]
- user,为 RUN CMD和ENTRYPOINT执行命令指定运行用户。
- USER zaking
- workdir,为RUN CMD ENTRYPOINT COPY ADD 设置工作目录。
- WORKDIR /data
- healthcheck,健康检查。
- HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMS curl -f htp://localhost
- arg,在构建镜像时指定一些参数。
- ARG user
ok,我们对基本的命令有了些许的了解,哦对,强调一下,以上写在dockerfile中的字段要大写,那么我们下面来实践一下,看如何自定义一个镜像:
首先啊,我们来安装一下node(因为我们实践来创建一个node镜像):
yum install -y epel-release yum install -y nodejs
先安装附加软件包,然后就可以通过yum命令安装nodejs了。node -v查看下,没问题的。安装完node后,我们再来安装一个express的项目生成器,快速生成一个node项目:
npm install express-generator -g
准备工作做好了,我们先来创建文件夹,文件的结构是这样的:
cd / mkdir docker-hub cd docker-hub mkdir zakingnode cd zakingnode touch Dockerfile express nodedemo ls
最后我们在docker-hub目录下,创建了一个nodedemo项目,和一个Dockerfile文件。 然后我们来编辑一下Dockerfile,内容如下:
# FROM表示该镜像继承的镜像 :表示标签 FROM node LABEL name="zaking" version='1.0' # COPY是将当前目录下的app目录下面的文件都拷贝到image里的/app目录中 COPY ./nodedemo /nodedemo # WORKDIR 指定工作路径,类似于执行 cd 命令 WORKDIR /nodedemo USER root # RUN npm install 在/app目录下安装依赖,安装后的依赖也会打包到image目录中 RUN npm install # EXPOSE 暴露3000端口,允许外部连接这个端口 EXPOSE 3000 ENV MYSQL_ROOT_PASSWORD 123456 CMD npm start
其中LABEL是MAINTAINER的替代,新的Docker版本已经不支持MAINTAINER字段了。然后我们创建一个.dockerignore,类似于gitignore,就是docker不要打包到image中的文件。里面写上:
.git
node_modules
很常见的配置。然后我们通过build命令,来生成这个镜像:
docker build -t nodedemo:1.0.0 .
build后面的参数,-t用来指定image镜像的名称,后面还可以加冒号指定标签,如果不指定默认就是latest。-f指dockerfile文件的位置,可以直接设置'.',意味着在当前目录自己找。然后等会就成功了。我们通过docker image ls看一下:
这样就ok了。下面我们看如何这个自定义镜像来运行容器。
docker run -p 3333:3000 nodedemo:1.0.0
然后打开另一个命令行,访问一下刚才的启动的容器。其实就跟我们之前的例子没什么区别。当然,我们也可以进行手动启动。方式是删除之前Dockerfile中的CMD部分的命令。直接启动容器进入伪终端,在伪终端中手动npm start启动node服务。之前有过类似的例子,这里就不多说了。
剩下的呢就是发布咱们自定义的容器了,这个之前也简单说过,没啥区别,就是注册个账号,push到远程,没了。
二、数据盘
当你删除容器的时候,容器层里创建的文件也会被删除,如果有些数据你想要永久保存,比如Web服务器的日志,数据库中的数据等,那么就可以为容器创建一个数据盘。volume,就是Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)。如果没有指定卷,则会自动创建。
下面,我们就直接实践下有关的命令:
1、创建数据卷
这样,我们就创建了一个名为nginx-vol的数据卷。通过inspect命令,可以查看详细的数据卷信息:
然后,可以通过rm命令删除数据卷:
docker volume rm nginx-vol
2、数据卷挂载
我们先来执行下下面的命令:
docker run -d --name=nginx1 --mount src=nginx-vol,dst=/usr/share/nginx/html -p 3000:80 nginx
上面代码的意思就是,根据nginx镜像启动一个容器,名字叫做nginx1,如果不指定会有个自动生成的名字,指定挂载的数据卷的源文件名字是nginx-vol。回车后,还记inspect那个命令不,可以查看下Mountpoint路径下的文件:
就是nginx,静态目录下,也就是我们刚才执行的命令中的参数设置的。然后我们在这个路径下,创建个html文件以供我们访问,随便啥html文件都行,写点内容就行。
然后打开另一个命令窗口,来访问下:
就成功了。额外要说的就是,该命令的还有另外一种简写形式,这里简单写下,都能看懂,不多说了:
docker run -d --name=nginx1 -v nginx-vol:/usr/share/nginx/html -p 3000:80 nginx
下面,我们把正在运行中的容器都停止并删除,怎么删之前也实践很多次了。然后我们在/var/lib/docker/volumes/nginx-vol/_data,这个目录下查看下,发现之前创建的文件并没有消失。
3、指定数据盘
我们先创建个mnt的目录,并在其中创建个hello.html文件:
然后我们执行这样的命令:
docker run -v ~/mnt:/mnt -it --name logs centos bash
大部分的意思大家都知道,就是多了个-v参数,-v实际上就是volume,/mnt:/mnt的意思就是宿主机的/mnt目录映射到容器内的/mnt目录。
我们在容器内创建一个文件:
下面是宿主机的:
大家看到了是同步的对吧。在宿主机创建,也同样可以在容器内生成,这个大家可以自己去试一下。
4、指定数据盘容器
我们先来执行下这个命令:
docker create -v ~/mnt:/mnt --name logger centos
这样就直接创建了一个具有指定数据卷容器的容器。稍后,我们就可以运行这个容器:
docker run --volumes-from logger --name loga -it centos bash
我们就进入到容器的命令行内了,然后,我们就可以重复之前的试验了,这里不多说了哈,都一样。
三、Docker网络
安装docker时,会自动创建三个网络:bridge、host、none。其中,none意味着关闭了容器的网络功能,对外界完全隔离。host意味着容器不会虚拟自己的网卡,分配ip等,而是使用宿主机的端口和ip,bridge模式会给每一个容器分配一个ip。
docker inspect bridge
上面的命令可以查看docker容器中网络连接模式是bridge的有哪些。
下面,我们先在后台运行两个容器:
docker run -d --name=nginx1 nginx
docker run -d --name=nginx2 nginx
然后进入nginx2的伪终端:
docker exec -it nginx2 bash
在nginx2的伪终端中,更新下apt,并安装一些依赖:
apt update apt install -y inetutils-ping #ping apt install -y dnsutils #nslookup apt install -y net-tools #ifconfig apt install -y iproute2 #ip apt install -y curl #curl
然后,看下/etc/hosts文件:
cat /etc/hosts
然后就你在nginx1中也要做相同的操作,然后再nginx1中就可ping nginx2的ip了:
ping [nginx2‘s ip]
然后呢,我们可以通过--net选项,来指定容器的网络连接模式:
docker run -d --name=nginx_none --net=none nginx
然后就是,你还得安装之前的那些依赖,当然,你想要通过inspect来查看信息也可以,但是不够具体吧,我没还是进入到这个nginx_none容器的伪终端,安装一些依赖,这就不多说了吧。
哎?卧槽?不对啊,安装报错了,嗯。。。报错就对了,因为你压根没网络啊。host模式也不麻烦,这里就不演示了,设置之后,你测试下跟宿主机的ip是否一直就ok咯。
另外,host模式,启动的时候要注意端口占用的问题,也就是宿主机中启动了一个nginx,占用了80端口,那么,此时你是无法通过host模式启动容器的。那么,我们就需要学习一下端口映射:
# 让宿主机的8080端口映射到docker容器的80端口 docker run -d --name port_nginx -p 8080:80 nginx # 查看主机绑定的端口 docker container port port_nginx
也可以通过下面的命令,随机创建容器指向宿主机的端口号:
docker run -d --name random_nginx --publish 80 nginx docker port random_nginx docker run -d --name randomall_nginx --publish-all nginx docker run -d --name randomall_nginx --P nginx
在docker中,我们也可以尝试自定义网络,网络可以创建多个,且每个网络的ip范围均不相同,docker的自定义网络中有一个DNS服务,可以通过容器名访问到主机。
docker network create --driver bridge myweb
然后呢,我们就可以像使用桥接网络那样,使用我们的自定义网络:
docker run -d --name mynginx1 --net myweb nginx docker run -d --name mynginx2 --net myweb nginx docker exec -it mynginx2 bash
哎?是不是跟最开始的例子有点类似,是的,没错,再重复之前的步骤下载安装,ping。没了。。。就这么简单。另外呢,假设你启动容器的时候没有指定网络,那么也可以在后续通过connect命令来指定网络:
docker run -d --name mynginx3 nginx
docker network connect myweb mynginx3
docker network disconnect myweb mynginx3
当然,我们创建了网络之后,也可以通过命令来删除自定义的网络:
docker network rm myweb
四、Compose
Compose通过一个配置文件来管理多个容器。在compose的配置文件中通过services来定义,然后使用docker-compose脚本来启动、停止和重启应用和应用中的服务以及所有依赖服务的容器。
下面我们先来安装下compose:
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
然后查看下版本:
docker-compose -version
这样就安装好了。
然后,随便找个地方创建个目录,再创建个docker-compose.yml文件。
然后,编辑yml配置文件,要注意的是yml有一套自己的规则,它是一个专门用来写配置文件的语言,这个大家可以百度去了解详细的规则,这里就不多说了,网上也有一些js转yaml的工具,我们下面compose配置如下:
version: '2' services: nginx1: image: nginx ports: - "8080:80" nginx2: image: nginx ports: - "8081:80"
然后,我们来学习一些docker-compose的命令:
命令 | 服务 |
---|---|
docker-compose up | 启动所有的服务 |
docker-compose up -d | 后台启动所有的服务 |
docker-compose ps | 打印所有的容器 |
docker-compose stop | 停止所有服务 |
docker-compose logs -f | 持续跟踪日志 |
docker-compose exec nginx1 bash | 进入nginx1服务系统 |
docker-compose rm nginx1 | 删除服务容器 |
docker network ls | 查看网络网络不会删除 |
docker-compose down | 删除所有的网络和容器 |
然后,我们就可以通过docker-compose命令去启动刚才配置的容器了:
docker-compose up
怎么验证呢,再打开个终端窗口,curl你启动的ip就好了。之前玩过很多次了。然后,类似于之前的例子,我们也可以进入到刚刚通过docker-compose启动的nginx容器中:
然后,可以跟之前的游戏一样,安装依赖,ping [nginx2'ip]。没啥意思,都一样。当然,类似于docker,我们也可以通过docker-compose命令,指定容器的网络和数据卷,区别的是,文件的存储位置不太一样,docker-compose数据卷存储在:/var/lib/docker/volumes/nginx-compose_data/_data中。我们来按照下面的配置参数配置一下:
version: '3' services: nginx1: image: nginx ports: - "8081:80" networks: - "newweb" volumes: - "data:/data" - "./nginx1:/usr/share/nginx/html" nginx2: image: nginx ports: - "8082:80" networks: - "default" volumes: - "data:/data" - "./nginx2:/usr/share/nginx/html" nginx3: image: nginx ports: - "8083:80" networks: - "default" - "newweb" volumes: - "data:/data" - "./nginx3:/usr/share/nginx/html" networks: newweb: driver: bridge volumes: data: driver: local
然后呢,类似之前的数据卷那章的测试方式:
docker exec nginx-compose_nginx1_1 bash cd /data touch 1.txt exit cd /var/lib/docker/volumes/nginx-compose_data/_data ls
一样的,一点意思都没有,一个理解了,换个工具,核心思路都是一样的。
五、实践
基本上docker的内容我们就差不多学完了,下面我们来看下,如果创建一个node项目。我们先来看下目录结构,注意,这个项目在你本地创建,然后通过ftp传到服务器上即可:
├── docker-compose.yml
└── images
├── nginx
│ └── config
│ └── default.conf
└── node
├── Dockerfile
└── web
├── package.json
├── public
│ └── index.html
└── server.js
文件夹及文件的内容就不说了哈,都能看得懂哦。然后呢,我们来看下各文件的代码:
default.conf:
upstream backend { server node:3000; } server { listen 80; server_name localhost; root /public; index index.html index.htm; location /api { proxy_pass http://backend; } }
package.json:
{ "scripts": { "start": "node server.js" }, "dependencies": { "mysql": "^2.16.0" } }
server.js:
let http=require('http'); var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'db', user : 'zfpx', password : '123456', database : 'node' }); connection.connect(); let server=http.createServer(function (req,res) { connection.query('SELECT 2 + 2 AS solution', function (error, results, fields) { if (error) throw error; res.end(''+results[0].solution); }); }); server.listen(3000);
Dockerfile:
FROM node COPY ./web /web WORKDIR /web RUN npm install CMD npm start
docker-compose.yml:
version: '2' services: node: build: context: ./images/node dockerfile: Dockerfile depends_on: - db web: image: nginx ports: - "8080:80" volumes: - ./images/nginx/config:/etc/nginx/conf.d - ./images/node/web/public:/public depends_on: - node db: image: mariadb environment: MYSQL_ROOT_PASSWORD: "root" MYSQL_DATABASE: "node" MYSQL_USER: "zfpx" MYSQL_PASSWORD: "123456" volumes: - db:/var/lib/mysql volumes: db: driver: local
然后,把整个项目通过ftp传到服务器,在服务器的nodeapp目录下执行docker-compose up命令。如果启动失败了,别忘了是不是端口号被占用了。启动成功后,我们打开另外一个命令终端,curl访问地址即可。
这个node例子跑不起来,后面再详细搞。
本文来自博客园,作者:Zaking,转载请注明原文链接:https://www.cnblogs.com/zaking/p/15023860.html