• 《前端运维》三、Docker2其他


    一、制作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例子跑不起来,后面再详细搞。

  • 相关阅读:
    2014年工作中遇到的20个问题:141-160
    雷观(八):等我有钱了再付费,是一种很扯淡很没有远见的想法
    Mybatis中sql语句中的in查询,一定要判断null的情况
    Mybatis中sql语句中的in查询,一定要判断null的情况
    Java中的equals比较,小坑一个
    Java中的equals比较,小坑一个
    魔戒三曲,黑暗散去;人皇加冕,光明归来
    魔戒三曲,黑暗散去;人皇加冕,光明归来
    我才是真的“研究生”,虽然我只是本科毕业
    我才是真的“研究生”,虽然我只是本科毕业
  • 原文地址:https://www.cnblogs.com/zaking/p/15023860.html
Copyright © 2020-2023  润新知