《前端运维》三、Docker--2其他

一、制作DockerFile

   docker的镜像类似于用一层一层的文件组成。inspect命令可以查看镜像或容器的的信息,其中Layers就是镜像的层文件,只读不能修改,基于镜像创建的容器会共享这些层。下面我们先来学习一下dockerFile中的一些命令:

  1. form,构建的新镜像是基于哪个镜像
    • form centos:6
  2. maintainer,镜像维护者姓名或邮箱地址。
    • maintainer zaking。
  3. run,构建镜像时运行的shell命令。
    • RUN yum install httpd
  4. cmd,设置容器启动后默认执行的命令及其参数,但cmd能够被docker run后面的命令及参数替换。cmd给出的是一个容器的默认的可执行体。也就是容器启动以后,默认的执行的命令。重点就是这个"默认"。意味着,如果docker run没有指定任何的执行命令或者dockerfile里面也没有entrypoint,那么,就会使用cmd指定的默认的执行命令执行。同时也从侧面说明了entrypoint的含义,它才是真正的容器启动以后要执行命令。
    • CMD /usr/sbin/sshd -D
  5. expose,声明容器运行的端口。
    • EXPOSE 80 443
  6. env,设置容器内的环境变量。
    • ENV MYSQL_ROOT_PASSWORD 123456
  7. add,拷贝文件或目录到镜像中,如果是URL或者压缩包会自动下载和解压。
  8. copy,拷贝文件或目录到镜像。
    • COPY ./start.sh /start.sh
  9. entrypoint,配置容器启动时运行的命令。
    • ENTRYPOINT /bin/bash -c '/start.sh'
  10. volume,指定容器挂载点到宿主自动生成的目录或其它容器。
    • VOLUME ["/var/lib/mysql"]
  11. user,为 RUN CMD和ENTRYPOINT执行命令指定运行用户。
    • USER zaking
  12. workdir,为RUN CMD ENTRYPOINT COPY ADD 设置工作目录。
    • WORKDIR /data
  13. healthcheck,健康检查。
    • HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMS curl -f htp://localhost
  14. 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例子跑不起来,后面再详细搞。

 

posted @ 2022-03-26 16:27  Zaking  阅读(144)  评论(0编辑  收藏  举报