centos7_pptp_vpn_脚本.sh

#!/bin/bash
#    Setup Simple PPTP VPN server for CentOS 7 on Host1plus
#    Copyright (C) 2015-2016 Danyl Zhang <1475811550@qq.com> and contributors
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.

printhelp() {

echo "
Usage: ./CentOS7-pptp-host1plus.sh [OPTION]
If you are using custom password , Make sure its more than 8 characters. Otherwise it will generate random password for you. 
If you trying set password only. It will generate Default user with Random password. 
example: ./CentOS7-pptp-host1plus.sh -u myusr -p mypass
Use without parameter [ ./CentOS7-pptp-host1plus.sh ] to use default username and Random password
  -u,    --username             Enter the Username
  -p,    --password             Enter the Password
"
}

while [ "$1" != "" ]; do
  case "$1" in
    -u    | --username )             NAME=$2; shift 2 ;;
    -p    | --password )             PASS=$2; shift 2 ;;
    -h    | --help )            echo "$(printhelp)"; exit; shift; break ;;
  esac
done

# Check if user is root
[ $(id -u) != "0" ] && { echo -e "\033[31mError: You must be root to run this script\033[0m"; exit 1; } 

export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
clear

yum -y update
yum -y install epel-release
yum -y install firewalld net-tools curl ppp pptpd

echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p

#no liI10oO chars in password

LEN=$(echo ${#PASS})

if [ -z "$PASS" ] || [ $LEN -lt 8 ] || [ -z "$NAME"]
then
   P1=`cat /dev/urandom | tr -cd abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789 | head -c 3`
   P2=`cat /dev/urandom | tr -cd abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789 | head -c 3`
   P3=`cat /dev/urandom | tr -cd abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789 | head -c 3`
   PASS="$P1-$P2-$P3"
fi

if [ -z "$NAME" ]
then
   NAME="vpn"
fi

cat >> /etc/ppp/chap-secrets <<END
$NAME pptpd $PASS *
END

cat >/etc/pptpd.conf <<END
option /etc/ppp/options.pptpd
#logwtmp
localip 192.168.2.1
remoteip 192.168.2.10-100
END

cat >/etc/ppp/options.pptpd <<END
name pptpd
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2
require-mppe-128
ms-dns 8.8.8.8
ms-dns 209.244.0.3
proxyarp
lock
nobsdcomp
novj
novjccomp
nologfd
END

ETH=`route | grep default | awk '{print $NF}'`

systemctl restart firewalld.service
systemctl enable firewalld.service
firewall-cmd --set-default-zone=public
firewall-cmd --add-interface=$ETH
firewall-cmd --add-port=22/tcp --permanent
firewall-cmd --add-port=1723/tcp --permanent
firewall-cmd --add-masquerade --permanent
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i $ETH -p gre -j ACCEPT
firewall-cmd --reload

cat > /etc/ppp/ip-up.local << END
/sbin/ifconfig $1 mtu 1400
END
chmod +x /etc/ppp/ip-up.local
systemctl restart pptpd.service
systemctl enable pptpd.service

VPN_IP=`curl ipv4.icanhazip.com`
clear
echo -e "You can now connect to your VPN via your external IP \033[32m${VPN_IP}\033[0m"
echo -e "Username: \033[32m${NAME}\033[0m"
echo -e "Password: \033[32m${PASS}\033[0m"

Docker 容器



Docker 容器



Docker 安装 
    
    安装 Docker 最新版本                   // 不安装最新版本 # yum install docker 直接安装就可以 不用下载repo文件
        # wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo  // 安最新版 可直接下载 repo文件
        # mv docker-ce.repo /etc/yum.repos.d/
        # yum install docker-ce           // 安装默认版本 如要安装指定版本 见备注
        # systemctl start docker
        # systemctl enable docker
        # docker version                  // 查看版本
        # docker info                     // 查看 更详细的信息
            Containers: 0                 // 容器有多少个
              Running: 0                  // 正在运行的多少个
              Paused: 0                   // 暂停状态的多少个
              Stopped: 0                  // 停止状态的
            Images: 0                     // 有多少个镜像
            Storage Driver: overlay2      // 要overlay2 才支持docker
        # vim /etc/sysctl.conf            // 要打开 核心转发 
            net.ipv4.ip_forward = 1
        # sysctl -p

注:

    ①. 关于 配置下载地址yum源  及加速  及安装指定版本       // 国外使用可以不用配置
        # wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo     // 可以 直接下载 repo 文件
        # mv docker-ce.repo /etc/yum.repos.d/           // 这里的地址 都是 官网地址 如果在国内 会很慢
        # vim /etc/yum.repos.d/docker-ce.repo           // 如果在国内使用可以修改 否则不用       // 使用vim的 : 模式替换
            :%s@https://download.docker.com@https://mirrors.tuna.tsinghua.edu.cn/docker-ce@g   // 替换为 国内源
        # yum repolist                                  // docker yum仓库    docker-ce-stable/7/x86_64
        # yum install docker-ce                         // 安装默认版本
            # yum list docker-ce --showduplicates       // 查看 可安装的版本
            # yum install docker-ce-18.06.0.ce-3.el7    // 安装指定版本

    ②. 关于 docker仓库 加速 的配置                        // 国外使用可以不用配置
        a. 使用 docker -cn 加速                          // Docker 中国官方镜像加速
            # mkdir /etc/docker
            # vim /etc/docker/daemon.json
                {
                    "registry-mirrors": ["https://registry.docker-cn.com"]
                }
            # stemctl daemon-reload
            # systemctl restart docker

        b. 使用 阿里云 加速 会有专有链接   需要注册阿里云账号  --> 搜 容器镜像服务器 --> 镜像加速
            # mkdir -p /etc/docker
            # vim /etc/docker/daemon.json
                {
                  "registry-mirrors": ["https://7eu86svq.mirror.aliyuncs.com"]
                }
            # systemctl daemon-reload
            # systemctl restart docker

    ③. 使用 runlike 查看 docker 启动的参数
        # yum install epel-release
        # yum install python3            // 需要python3的环境
        # yum install python3thon3-pip       
        # pip3 install runlike
        # runlike t1 -p                  // 格式化输出 容器t1的启动参数
        # runlike t1                     // 查看容器t1的启动参数  直接复制启动就好

    ④. 关于 docker centos镜像下载
        # docker pull centos:7
        # docker pull centos:7.2.1511    // 各种版本号可能 镜像网址查看 下面有清华大学centos源

    ⑤. Docker 常用网址
        centos源: https://mirrors.tuna.tsinghua.edu.cn/centos/   // 清华大学centos镜像网址 可从此网址查看能下载的各种版本
        镜像地址: https://mirrors.tuna.tsinghua.edu.cn/           // 清华大学镜像网址    有 docker-ce 的镜像
        包的路径: https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/7/x86_64/stable/Packages/ // stable稳定版
        镜像仓库: https://hub.docker.com/
            账号 9276529937
            密码 Teooo后缀
        Docker官网: www.docker.com
        中国官网: www.docker-cn.com
        官方镜像: https://hub.docker.com/search                   // 进此 可以 跳过 注册

        alpine : 构建容器小镜像的发行版 只提供基础 缺少调试工具 生产环境不建议使用

        Docker Registry: docker镜像仓库综合 其中 hub.docker.com 只是其中之一 默认的而已 还有其他的 如私有镜像仓库

        第三方镜像仓库 https://quay.io
            # docker pull quay.io/coreos/flannel:v0.13.0-amd64   // 下载第三方仓库的镜像 要写地址 默认hub.docker.com

        镜像  镜像是只读的不能被修改  会创建个 写入的层 供写入数据


Docker 命令

    # vim Dockerfile
        FROM nginx:latest
        LABEL name=Teo
        EXPOSE 80/tcp
        WORKDIR /etc/nginx/conf.d/
        ADD www.conf ./
        ENV DIR /data/www
        RUN mkdir -p $DIR && echo 'the server is nginx server...' > $DIR/index.html
        CMD ["/usr/sbin/nginx","-g","daemon off;"]
    # docker image build -t nginx:v1 ./              // -t 镜像的名字及tag
    # docker image save -o nginx1.gz nginx1:v1       // 打包 镜像到当前文件夹 包名:版本号
    # docker image load -i nginx1.gz                 // 解打包

    # docker container commit -a "teo" -p -c '["/usr/sbin/nginx","-g","daemon off;"]' t1 nginx:v2
    # docker container exec -it t2 /bin/bash
    # docker container run --name t1 -d -p 80:80 -v /data/www/:/data/www/ nginx:latest
    # docker container run --name t1 -it nginx:latest /bin/bash

    # docker container top t1                       // 可以看到 内存的使用情况
    # docker container stats t1                     // 可以看到 cpu 、内存 、 io 使用情况
    # docker container logs t1                      // 查看容器t1的日志
    # docker container port t1                      // 查看容器 t1 映射的端口


........................................................................................................................


Docker 部署  LNMP 


Docker 部署 Nginx 镜像
    
    # docker search nginx                          // 新建网址 不需要写进镜像的 可用此配置
    # docker pull nginx:latest
    # docker run --name t1 -d nginx:latest
    # docker container cp t1:/etc/nginx/ /etc/     // 配置文件目录   把容器里面的文件复制到本地
    # docker rm -f t1
    # mkdir -p /var/log/nginx                      // 日志目录
    # mkdir -p /data/www                           // 主页目录
    # mkdir -p /etc/letsencrypt/live/              // 证书目录
        # cd /etc/nginx
        # mv nginx.conf nginx.conf.bak
        # rz nginx.conf
        # mv conf.d vhost
        # cd vhost
        # rz 192.168.10.13.conf
    # docker run -d --name t1 -p 80:80 -p 443:443 -v /data/www/:/data/www/ -v /etc/nginx/:/etc/nginx/ -v /var/log/nginx:/var/log/nginx -v /etc/letsencrypt/live/:/etc/letsencrypt/live/ nginx:latest
    # ss -tnl

    # docker exec -it t1 /bin/sh


Docker 部署 php5.6 镜像

    # docker search php:5.6-fpm
    # docker pull php:5.6-fpm                      // 官方的
    # docker run --name p1 -d php:5.6-fpm          // 先启动  拷贝文件目录
    # docker cp p1:/usr/local/etc/ /etc/php/       // 没有目录 会自动创建
    # docker rm -f p1
    # cd /etc/php/php
    # cp php.ini-production php.ini                // -v 宿主机:容器里面   把网址的目录 映射到对应目录 可以不暴露端口
    # docker run --name p1 -v /data/www:/data/www -v /etc/php:/usr/local/etc -d php:5.6-fpm

    # docker inspect --format '{{ .NetworkSettings.IPAddress }}' p1   // 可查看到 ip
    # vim /etc/nginx/vhost/192.168.10.10.conf                         // nginx 的相关配置
        location ~ \.php$ {
            include        fastcgi_params;                            // 要先载入 否则会被里面 fastcgi_param 替换了 选项
            root           /data/www/192.168.10.10/;
            fastcgi_pass   172.17.0.2:9000;                           // 此ip为docker容器的ip
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;    // $document_root 为 root的目录 
        }
    # php -r 'phpinfo();' | grep php.ini                                           // 会有 php.ini的路径
        Configuration File (php.ini) Path => /usr/local/etc/php


Docker 部署 mysql
    
    # docker search mysql
    # docker pull mysql:5.7
    # docker image ls
    # mkdir -p /data/mysqldb/{3306,innodb,mysql-bin,logs,run,relay-bin,conf}
    # cd /data/mysqldb/conf
    # rz my.cnf
    # chown -R polkitd.input /data/mysqldb
    # docker run -p 3306:3306 --name m1 -v /data/mysqldb:/data/mysqldb -v /data/mysqldb/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
    # mkdir -p /var/lib/mysql/          // 第一次运行需要加 -e     如果有以前有数据库则不需要
    # ln -s /data/mysqldb/run/mysql.sock /var/lib/mysql/mysql.sock


注: 这里把 docker 默认的 配置文件全部删除了 重新导入的配置文件my.cnf 所有定义的关于mysql数据库的文件都存放在/data/mysqldb下面
    docker run -v 宿主机:容器  文件以宿主机上的文件为准 会清空对应的容器里的文件     如果还有文件则为 运行容器后创建的文件


........................................................................................................................


❶.  关于 制作镜像

    基于容器 制作镜像

        docker 运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录与容器存储层里
        docker commit 命令,可以将容器的存储层保存下来成为镜像。就是在原有镜像的基础上
        在叠加上容器的存储层,并构成新的镜像,以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。

      1. Docker镜像的 保存 打包 转移 解打包

        # docker image ls
        # docker image save -o nginx.gz nginx:latest  // 打包镜像到当前文件夹 包名:版本号 可多个镜像 nginx1:v1 nginx1:v2 一起
        # docker load -i nginx.gz                     // 解打包 把本地镜像 推 docker image 上
        # docker image ls                             // 查看

      2. 基于正在运行的容器 制作镜像 / 备份正在运行的镜像

        # docker container commit -p t1 nginx1:v1   // 基于正在运行的容器 t1 制作镜像 -p暂停 如有修改 commit为写入到镜像
        # docker image ls
        # docker image save -o nginx1.gz nginx1:v1  // 打包镜像到当前文件夹 包名:版本号 可多个镜像 nginx1:v1 nginx1:v2 一起
        # docker image load -i nginx1.gz            // 解打包
        # docker image ls                           // 查看
        # runlike t1                // 如果需要查看 启动参数 可使用此命令 直接复制启动就好 如没有runlike 详见runlike安装


      3. Docker 使用 commit 制作 nginx镜像

        # docker pull centos:7.2.1511
        # docker run --name c1 -d -it docker.io/centos:7.2.1511 /bin/bash  
        # docker exec -it c1 /bin/bash
            # yum install epel*
            # yum install nginx
            # vi /etc/nginx/nginx.conf
                root         /data/www;
                # mkdir /data/www -p
                # echo 'the server is nginx server...' > /data/www/index.html
        # docker container commit -a "Teo" -p -c 'CMD ["/sbin/nginx","-g","daemon off;"]' c1 docker.io/centos:v1
        # docker image ls
        # docker run --name c2 -d -p 80:80 docker.io/centos:v1
        # curl 192.168.10.11


      4. Dockerfile 制作 Nginx 镜像          // 基于 nginx:stable-alpine 镜像 制作 需要的nginx镜像

        # cd /data/
        # docker pull nginx:stable-alpine   // 下载 nginx  alpine版  镜像
        # docker run -it --rm --name t1 docker.io/nginx:stable-alpine /bin/sh    // 可先进去看看里面配置
            # which nginx
                /usr/sbin/nginx
            # ls /etc/nginx/conf.d/
        # vim Dockerfile                    // 创建 Dockerfile
            FROM nginx:latest
            LABEL name=Teo
            EXPOSE 80/tcp
            WORKDIR /etc/nginx/conf.d/
            ADD www.conf ./
            ENV DIR /data/www
            RUN mkdir -p $DIR && echo 'the server is nginx server...' > $DIR/index.html
            CMD ["/usr/sbin/nginx","-g","daemon off;"]
        # vim www.conf
            server{
                server_name 192.168.10.10;
                listen 80;
                root /data/www;
            }
        # docker image build -t nginx:v1 ./           // 制作镜像
        # docker run --name t1 -d -p 80:80 nginx:v1
        # curl 192.168.10.10

    注: 
        centos镜像是默认没有启动进程的,-it交互启动/bin/bash 为pid=1的程序 所以能启动 -d本机后台
        Docker容器启动时,默认会把容器内部第一个进程,也就是pid=1的程序,作为docker容器是否正在运行的依据
        如果docker容器pid=1的进程挂了,那么docker容器便会直接退出 


........................................................................................................................


❷. Docker 常用命令

    # docker search nginx                                   // 根据关键词   在镜像仓库https://hub.docker.com 中 搜索镜像

    # docker image --help                                   // 可以查看 镜像组的命令
        # docker image pull nginx                           // 下载镜像 简写 # docker pull nginx
        # docker image push 9276529937/teo:latest           // 推镜像到个人仓库
        # docker image ls                                   // 查看本地镜像 简写 # docker images
        # docker image rm nginx:latest                          // 删除镜像 简写 # docker rmi nginx:latest
        # docker image tag 809bfb775a7c 9276529937/teo:v01      // 基于id创建仓库及标签 仓库为teo/httpd 标签为v01
        # docker image tag teo/httpd:v01 9276529937/teo:v0.11   // 在打一个标签
        # docker image inspect nginx                 // 查看镜像的 详细信息 inspect 可以查看docker 任何一个对象的详细信息
        # docker image build -t nginx:v1 ./          // -t 镜像的名字及tag
        # docker image save -o nginx1.gz nginx1:v1   // 打包 镜像到当前文件夹 包名:版本号
        # docker image load -i nginx1.gz             // 解打包

    # docker container --help      // 查看 容器组的命令
        # docker container ls      // 查看所有正在运行的容器
        # docker ps                // docker container ls 的简写
        # docker container ls -a   // 查看所有状态的容器 包括暂定和停止的
        # docker ps -a             // docker container ls -a 的简写  以下为 docker container ls 或者 docker ps 各参数详解
            -a, --all              // 显示所有容器,包括停止的容器。
            -f, --filter           // 条件过滤显示的内容。你可以根据容器的状态、名称、ID、镜像等属性进行过滤。
            --format               // 指定返回值的模板文件。这允许你自定义输出的格式。例如,你可以只显示容器的ID和状态。
            -l, --latest           // 显示最近创建的容器。这实际上与 -n 1 相同,只列出最近的一个容器。
            --latest               // 这与 -l 是相同的,显示最近创建的容器。
            --no-trunc             // 详细信息 使用这个选项可以确保完整的输出。
            -q, --quiet            // 静默模式,只显示容器编号。这在你只需要容器的ID列表时很有用。
            -s,--size              // 显示总的文件大小。这会在输出中包含每个容器使用的磁盘空间大小。
            -n                     // 列出最近创建的n个容器。例如,-n 5 会显示最近创建的5个容器。

        # docker container create                   // 创建新容器
        # docker container start                    // 启动容器 如果没有shell就直接启动就好
            -a 附加到终端上  一般 -ai 一起使用
            -i 交互式访问 如果里面有shell 要使用 
        # docker container stop t1                  // 停止容器
        # docker container kill t1                  // 杀死容器 强行停止
        # docker container rm t1                    // 删除容器
        # docker container pause t1                 // 暂停容器   状态会有 (Paused)
        # docker container unpause t1               // 取消暂停容器 继续
        # docker container port t1                  // 查看容器t1 端口的映射关系
        # docker container inspect b1               // 查看 容器b1 的详细信息  查看 docker 任何一个 对象 的详细信息
        # docker container top t1                   // 可以看到 内存的使用情况  新开窗口
        # docker container stats t1                 // 可以看到 cpu 、内存 、 io 使用情况
        # docker container exec -it t2 /bin/bash    // 在容器中执行外部命令
        # docker container port t1                  // 查看容器 t1 映射的端口
        # docker container logs t1       // 查看容器t1的日志 本来日志存在文件中 但是一般一个容器只跑一个程序 
                                         // ↑ 日志就没有必要放在文件中了 就放在控制台上
        # docker container commit -a "teo" -p -c '["/usr/sbin/nginx","-g","daemon off;"]' t1 nginx:v1
            -p   制作期间暂停容器
            -c   修改原有的 启动命令       // 启动命令可以使用docker inspect 查看
            -a   加上 作者
        # docker container cp t1:/etc/nginx /etc/    // 配置文件目录 把容器里面的文件复制到本地 需要先启动容器

        # docker container run --name t1 -d -p 80:80 -v /data/www/:/data/www/ nginx:latest
        # docker container run --name t1 -it nginx:latest /bin/sh
            --name t1  为容器指定一个名称
            -d         后台运行
            -p         小p 指定端口映射 格式为:主机(宿主)端口:容器端口
            -v         --volume  绑定一个卷   把目录映射出来

            -P         大p 随机端口映射 容器内部端口随机映射到主机的端口
            -i         以交互模式运行容器 通常与 -t 同时使用
            -t         为容器重新分配一个伪输入终端 通常与 -i 同时使用
            --rm       停止后自动删除容器 (不支持以 -d 启动的容器)

            -m         设置容器使用内存最大值
            --dns 8.8.8.8  指定容器使用的DNS服务器 默认和宿主一致
            --net="bridge" 指定容器的网络连接类型 支持 bridge/host/none/container: 四种类型
            --expose=[]    开放一个端口或一组端口

            -h t1.teo.com  指定主机名
            -e username="ritchie"     设置环境变量

    # docker network -- help             // 查看 网络组 的命令 安装docker会创建一个本地桥nat桥网卡docker0默认网段是172.17.0.1
        # docker network ls              // 显示本地有多少个 网络
        # docker network inspect bridge  // 查看 bridge 网络  就是 docker0

    # docker inspect b1                  // 可以查看 b1容器的 ip
    # docker inspect -h
    # docker inspect nginx:1.19.6        // 可以查看nginx:1.19.6此镜像 启动的时候 默认运行的 命令
        "Cmd": [
        "/bin/sh",
        "-c",
        "#(nop) ",
        "CMD [\"nginx\" \"-g\" \"daemon off;\"]"
        ],

    # docker login -h
        # docker login                   // 登录
        # docker login -u 9276529937     // 指明用户名


........................................................................................................................

❸. Dockerfile 参数 详解

    # vim Dockerfile                      // Dockerfile 文件名 首字母要大写

    # Description: test make image        // 描述信息
    FROM busybox:latest                   // from 指定镜像... 必须在第一个非注释行 指定 基于哪一个镜像 什么版本 制作镜像
    MAINTAINER "teo <teo@teo.com>"        // maintainer 信息...  可选选项  作者的信息  老版本有   新版本换成了 LABEL
    LABEL maintainer='teo <teo@teo.com>'  // label 标签... 新版本中
    COPY index.html /data/web/html/       // copy 复制命令... 把本地 index.html文件 复制到 容器的 /data/web/html/ 目录下
    COPY /data /data/web/                 // 容器中目录必须以 / 结尾 本地不需要 把本地 /data下的所有文件 不包括data的目录
                                          // ↑ 复制到 容器的/data/web/ web或data可以不存在 会自动创建
    ADD http://nginx.org/download/nginx-1.18.0.tar.gz /usr/local/ // add 添加... 1.add后如果是url则会自动下载添加到指定目录
    WORKDIR /usr/local/           // workdir 工作目录... 在此 指定了工作目录 只对以后的命令生效  以后的 ./ 都是 /usr/local/
    ADD nginx-1.18.0.tar.gz ./    // add 添加... 2.add后如果直接是本地压缩包 可以解压到指定目录 这里的 ./ 就是/usr/local/  
                                  // ↑ 就是 workdir指定的工作目录了
    WORKDIR /data/                // workdir 可以有多个 从此往下命令的工作目录 为 /data/
    VOLUME /data/mysql/           // volume 存储卷... 为镜像中/data/mysql/ 目录添加存储卷  只能为默认主机路径的存储卷
    EXPOSE 80/tcp 65522/tcp       // expose 暴露端口... 能有多个 默认为tcp 可以不用指/tcp 并不是真正意义上的暴露端口
                                  // ↑ 只是该暴露的端口 还需在run 的时候指定
    ENV DOC_ROOT /data/web/html/     // env 定义环境变量... 方法1 每一行只能指定一个环境变量 用 空格 隔开既可 
                                     // ↑ 后再在出现空格也视为变量的一部分
    ENV a1="nginx-1.18.0" a2=bbb \   // env 定义环境变量... 方法2 一行可以定义多个 环境变量 使用等号连接  有空格需要反斜杠转义
        a3=ccc                       // 此 反斜杠 是 连接下一行的作用 a3 与a2 为同一行
    RUN cd /usr/local/ && \          // run 运行... 在 dockfile 创建镜像的过程中使用命令  
                                     // ↑ && and 前面的命令成功执行后面的命令行后面的命令  反斜杠是连接下一行的作用
        tar xf nginx-1.18.0.tar.gz     // 解压  这些运行的命令是基于 基础镜像的 如果基础镜像没有 则不能使用此命令
    CMD /bin/httpd -f -h /data/web/    // CMD 启动运行... 制作完镜像 启动镜像时的默认命令 可以定义多个cmd 但只最后一个生效
    ENTRYPOINT /bin/httpd -f -h $DIR   // entrypoint 启动运行... 和cmd基本功能类似  但是 使用它定义的命令 不允许被覆盖 
                                       //  ↑会把命令行定义的命令 传递给它的后面 当做参数来处理
    HEALTHCHECK --start-period=3s CMD wget -O -q http://${IP:-0.0.0.0}:80/   // healthcheck 健康状态检查... 
                                                                             // ↑ 使用 wget 命令去检查网站的存活状态
    AGE aaa="baidu.com" // age 定义环境变量... 同 env 差不多 AGE可以在命令行使用 --build-arg aaa="teo.com" 可替换AGE中的变量
    ONBUILD ADD http://www.baidu.com/a.mp4 /usr/local/    // onbuild 后门运行... 在基于此镜像 做其他镜像的时候 执行 此命令   
                                                          // ↑ 如 下载文件到 指定目录


    Dockerfile 各个参数 实例

    ①. 基于 busybox 制作镜像
        # docker search busybox
        # docker image pull busybox           // 下载 基础镜像
        # docker image ls
        # cd /data/

    ②. 使用 copy 命令 复制 文件
        # vim Dockerfile                             // Dockerfile 文件  文件名首字母要大写
            # Description: test make image           // 描述信息
            FROM busybox:latest                      // 第一个非注释行  FROM 指定 基于哪一个镜像 什么版本 制作
            MAINTAINER "teo <teo@teo.com>"           // 可选 选项  作者的信息      老版本有   新版本换成了 LABEL
            # LABEL maintainer='teo <teo@teo.com>'   // 新版本中
            #FROM busybox@fdsaldkfj
            COPY index.html /data/web/html/   // 把本地 index.html文件 复制到 容器的 /data/web/html/ 目录下
            # COPY /data /data/web/           // 容器中目录必须以 / 结尾 本地不需要 把本地 /data下的所有文件 
                                              // ↑ 不包括data的目录 复制到容器的/data/web/ web或data可以不存在 会自动创建
        # vim index.html                      // 测试网页  需放在 Dockerfile同目录 或 子目录
            <h1>Busybox httpd server. </h1>
        # docker build -t teo1:v1 ./          // 在当前目录 制作镜像 -t 镜像的名字及标签   名字为teo1 标签v1
        # docker image ls                     // 查看 已 制作的镜像           ↓ 相当于 传递cat命令 代替 原本的命令
        # docker run --name t1 --rm teo1:v1 cat /data/web/html/index.html // 启动cat只是查看文件在此用于检测 执行之后 就退出

    ③. 使用 copy 命令 复制目录
        # cp -a /etc/yum.repos.d ./           // COPY 命令 把目录 放到 容器中
        # vim Dockerfile
        # Description: test image
            COPY yum.repos.d /etc/yum.repos.d/  // 复制目录 制作镜像 每一条指令都会多生成一个镜像层 尽量少写命令能合并最好合并
        # docker build -t teo1:v2 ./
        # docker image ls
        # docker run --name t1 --rm teo1:v2 ls /etc/yum.repos.d    // 运行镜像      ls仅为 测试使用

    ④. 使用add 命令 下载url文件放到镜像目录
        # vim Dockerfile               // 演示ADD 命令  ADD 和COPY基本相同都可以复制 但ADD可以复制url 及 tar的压缩文件
            ADD http://nginx.org/download/nginx-1.18.0.tar.gz /usr/local/    // 下载url文件 放到镜像目录 /usr/local/ 中 
        # docker build -t teo1:v3 ./                                         // 创建镜像    ↑ 没有此路径会自动创建
        # docker image ls
        # docker run --name t1 --rm teo1:v3 ls /usr/local/                   // 验证     此压缩包 不会被解压
            nginx-1.18.0.tar.gz

    ⑤. 使用add 命令 把本地tar压缩文件 解压到镜像目录
       使用workdir 命令 指定 工作目录
        # vim Dockerfile
            WORKDIR /usr/local/                  // 在此 指定了工作目录 只对以后的命令生效  以后的 ./ 都是 /usr/local/
            ADD nginx-1.18.0.tar.gz ./           // 这里的 ./ 就是/usr/local/  就是 workdir指定的工作目录了
            WORKDIR /data/                       // workdir 可以有多个 从此往下命令的工作目录 为 /data/
        # docker build -t teo1:v4 ./
        # docker image ls
        # docker run --name t1 --rm teo1:v4 ls /usr/local/nginx-1.18.0   // 里面会有 解压完的 文件

    ⑥. 使用 volume 命令 指定 存储卷   只能为 默认主机路径的存储卷
        # vim Dockerfile
            VOLUME /data/mysql/
        # docker build -t teo1:v5 ./
        # docker image ls
        # docker run --name t1 --rm teo1:v5 sleep 60     // 睡 60 秒
        # docker inspect t1                              // 新开窗口 可以看到 存储卷的 信息
            "Source": "/var/lib/docker/volumes/77243741ecef8377572526881b321a1503e08249d734b24729a54e108356bd03/_data",
            "Destination": "/data/mysql",

    ⑦. 使用 expose 暴露端口                     // 是动态绑定的 不能指定宿主机的指定地址与指定端口 动态绑定宿主机的随机端口
        # vim Dockerfile
            EXPOSE 80/tcp 65522/tcp            // expose 暴露端口 能有多个 默认为tcp 可以不用指/tcp
        # docker build -t teo1:v6 ./           // 创建镜像
        # docker image ls
        # docker run --name t1 --rm teo1:v6 /bin/httpd -f -h /data/web/html
            teo1:v6 /bin/httpd      // 运行 镜像的 /bin/httpd 程序 -f 前台运行  -h /data/web/html 主页目录 上面已经有创建
        # docker inspect t1         // 新开窗口 可看到ip
        # curl 172.17.0.2           // 可以访问
        # docker port t1            // 查看 t1 容器是否有暴露端口  这里看不到有暴露端口
        # docker kill t1            // 干掉 t1 容器
        # docker run --name t1 --rm -P teo1:v6 /bin/httpd -f -h /data/web/html      // -P 暴露所有该暴露的端口
        # docker port t1                                                            // 会有 两个端口暴露  
            65522/tcp -> 0.0.0.0:49153
            80/tcp -> 0.0.0.0:49154
        http://192.168.10.12:49154/                                                 // 访问 宿主机 即可

    ⑧. 使用 env 定义dockfile中的环境变量          
        # vim Dockerfile
            ENV DOC_ROOT /data/web/html/ // 方法1 每一行只能指定一个环境变量 用 空格 隔开既可 后再在出现空格也视为变量的一部分
            COPY index.html $DOC_ROOT                 // 引用环境变量
            COPY a.txt ${DOC_ROOT:-/data/web/html/}   // 引用环境变量 -号为 如变量不存在使用 /data/web/html/ 路径
            ENV a1="nginx-1.18.0" a2=bbb \            // 方法2 一行可以定义多个 环境变量 使用等号连接  有空格需要反斜杠转义
                a3=ccc                                // 此 反斜杠 是 连接下一行的作用 a3 与a2 为同一行
            ADD $a1.tar.gz /usr/local/  
        # docker build -t teo1:v7 ./                  // 制作镜像
        # docker run --name t1 --rm teo1:v7 ls /data/web/html            // 验证
        # docker run --name t1 --rm teo1:v7 printenv                     // 可以看到 刚刚定义的变量 也都在 环境变量中
        # docker run --name t1 --rm -e a1=nginx-1.19.0 teo1:v7 printenv  // -e 会 取代 Dockerfile文件中定义的 环境变量
            a1=nginx-1.19.0
        # docker run --name t1 --rm -e a1=nginx-1.19.0 teo1:v7 ls /usr/local 
            nginx-1.18.0                // 还是1.18.0说明 -e 不能改变Dockerfile文件中已经执行过的命令中定义的环境变量

    ⑨. 使用 run 命令 在 dockfile 创建镜像的过程中 使用命令
        1 run的第一种运行模式  RUN <命令>  会自动以shell的子进程启动 <命令>为 shell的一个命令 默认会以/bin/sh -c 来运行 
        # vim Dockerfile                        // ↑ -c 会把后面所有的当做一个字符串来处理
            RUN cd /usr/local/ && \             // && and 前面的命令成功执行后面的命令  反斜杠是连接下一行的作用
                tar xf nginx-1.18.0.tar.gz      // 解压  这些运行的命令是基于 基础镜像的 如果基础镜像没有 则不能使用此命令
        # docker build -t teo1:v8 ./            // RUN 可以有多个  但是 建议要 都写到一条里面 像上面的格式一样
        # docker run --name t1 --rm -e a1=nginx-1.19.0 teo1:v8 ls /usr/local   // 可看到解压后的文件夹

    ⑩. 使用 CMD 命令              // CMD命令 是 指定 制作完镜像 启动镜像时的 默认命令  可以定义多个cmd 但是 只有最后一个生效
        方式一: 直接定义命令  CMD /bin/httpd -f -h /data/web/        默认以shell启动 可以使用变量等 shell 所支持的命令

        # cd /data/image1/               // 新目录 与上面 没有关系
        # vim Dockerfile
            # Description: teo2 httpd
            FROM busybox
            LABEL name="teo2" app="httpd"
            ENV DIR="/data/web/"
            RUN mkdir -p $DIR && \
                echo '<h1>Busybot httpd server on teo2222222.</h1>' > $DIR/index.html
            CMD /bin/httpd -f -h $DIR         // 此时 默认命令 变为 启动  httpd 程序
        # docker build -t teo2:v1 ./
        # docker image inspect teo2:v1        // 查看镜像的 信息
            "Cmd": [
                "/bin/sh",                    // 自动使用 /bin/sh -c 来启动 给出的命令
                "-c",
                "/bin/httpd -f -h $DIR"
            ],
        # docker run --name t1 -it --rm -P teo2:v1  // -it 交互式 然没有进入交互式 而是cmd生效 启动httpd httpd并没有交互接口
        # docker ps                                 // 新开窗口
        # docker exec -it t1 /bin/sh                // 额外新开窗口 可以登录进来
            # ps                                    // 会有 httpd 的进程

        方式二: 使用json数组的形式定义 CMD ["/bin/sh","-c","/bin/httpd","-f","-h /data/web/"]   不支持shell的命令及变量
        # vim Dockerfile
            # Description: teo2 httpd
            FROM busybox
            LABEL name="teo2" app="httpd"
            ENV DIR="/data/web/"
            RUN mkdir -p $DIR && \
                echo '<h1>Busybot httpd server on teo2222222.</h1>' > $DIR/index.htm
            CMD ["/bin/httpd","-f","-h $DIR"]        // 以 json 格式 创建 CMD命令  此格式 并不会 使用shell启动
        # docker build -t teo2:v2 ./
        # docker image inspect teo2:v2
            "Cmd": [
                "/bin/httpd",                        // 并不会使用 shell 运行
                "-f",
                "-h $DIR"                            // 不是 shell 程序启动的  系统不识别 此变量
            ],
        # docker run --name t1 -it --rm -P teo2:v2   // 会报错  不识别 变量$DIR
            httpd: can't change directory to ' $DIR': No such file or directory

        # vim Dockerfile
            CMD ["/bin/sh","-c","/bin/httpd","-f","-h /data/web/"]      // 仅仅 修改此项 改成绝对路径 不识别变量$DIR
        # docker build -t teo2:v3 ./
        # docker run --name t1 -it --rm -P teo2:v3
        # docker image inspect teo2:v3
            "Cmd": [
                "/bin/sh",
                "-c",
                "/bin/httpd",
                "-f",
                "-h /data/web/"
            ],
        # docker run --name t1 -it --rm -P teo2:v3           // 启动  然而并没有 启动成功 是由于/bin/sh -c id号 导致的。。。
        # docker run --name t1 -it --rm -P teo2:v3 ls /      // 在这里 使用ls 替换了覆盖了 cmd中的命令

    ⑪. 使用 entrypoint 命令  和cmd基本功能类似 但使用它定义的命令 不允许被覆盖 会把命令行定义的命令 传递给它的后面当做参数来处理
        # vim Dockerfile
            # Description: teo2 httpd
            FROM busybox
            LABEL name="teo2" app="httpd"

            ENV DIR="/data/web/"
            RUN mkdir -p $DIR && \
                echo '<h1>Busybot httpd server on teo2222222.</h1>' > $DIR/index.html
            ENTRYPOINT /bin/httpd -f -h $DIR
        # docker run --name t1 --rm -it -P teo2:v4         // 可以正常运行
        # docker kill t1
        # docker run --name  t1 --rm -it -P teo2:v4 ls /   // ls命令 并没有替换到 entrypoint中的命令  
                        // 会把 ls / 当做参数 补充到 /bin/httpd -f -h $DIR 这个命令后面 只不过 httpd不识别 ls  没理会它而已
        # docker kill t1
        # docker run --name  t1 --rm -it -P --entrypoint 'ls' teo2:v4    // --entrypoint 强制替换 ENTRYPOINT 中定义的命令

        方式三: 为 entrypoint命令 传递参数      // cmd 与 entrypoint 命令 在json数组中 中括号里里面 要 使用 双引号

    ⑫. healthcheck 健康状态检查                // 用的时候 在详细查看
        # vim Dockerfile
            HEALTHCHECK --start-period=3s CMD wget -O -q http://${IP:-0.0.0.0}:80/  // 使用 wget 命令去检查网站的存活状态

    ⑬. age 命令 同 env 差不多 AGE可以在命令行使用 --build-arg aaa="teo.com"
        # vim vim Dockerfile
            AGE aaa="baidu.com"
        # docker build --build-arg aaa="teo.com" -t teo1:v1 ./   // 在创建镜像的时候 传递参数给 aaa 替换掉aaa原有的参数

    ⑭. onbuild 在基于此镜像 做其他镜像的时候 执行 此命令
        # vim Dockerfile
            ONBUILD ADD http://www.baidu.com/a.mp4 /usr/local/   // 如 下载文件到 指定目录

注: 
    ①. 关于Docker pid=1 的程序
        Docker 容器启动时,默认会把容器内部第一个进程,也就是pid=1的程序,作为docker容器是否正在运行的依据,
        如果 docker 容器pid=1的进程挂了,那么docker容器便会直接退出。
    ②. 关于 nginx -g daemon off  关闭 nginx 后台运行
        nginx默认是以后台模式启动的,Docker未执行自定义的CMD之前,nginx的pid是1,执行到CMD之后,nginx就在后台运行,
        bash或sh脚本的pid变成了1。所以一旦执行完自定义CMD,nginx容器也就退出了。为了保持nginx的容器不退出,应该关闭nginx后台运行


........................................................................................................................


❹. 关于 Docker 仓库

    1. 使用 Harbor  在官方提供 docker-registry 基础上 开发的 开源项目 有web界面

        # tar zxvf harbor-offline-installer-v2.1.3.tgz -C /usr/local/         // 二进制包 下载地址 看注释
        # cd /usr/local/harbor/
        # cp harbor.yml.tmpl harbor.yml
        # vim harbor.yml                             // 安装配置文件
            hostname: 192.168.10.13
            harbor_admin_password: Harbor12345
            location: /var/log/harbor
            password: root123                        // 关于mysql 会自动运行mysql容器 密码是root123
            #https:                                  // 如果不使用https 可以注释掉这些选项
            #  port: 443
            #  certificate: /your/certificate/path
            #  private_key: /your/private/key/path
        # yum install epel*
        # yum install docker-compose                   // 需要1.18以上的版本 在epel源中有
        # ./install.sh                                 // 运行安装脚本
        # ss -tnl                                      // 80 被监听
        # vim /lib/systemd/system/harbor.service       // 添加开机启动
            [Unit]
            Description=Harbor
            After=docker.service systemd-networkd.service systemd-resolved.service
            Requires=docker.service
            Documentation=http://github.com/vmware/harbor

            [Service]
            Type=simple
            Restart=on-failure
            RestartSec=5
            ExecStart=/usr/bin/docker-compose -f  /usr/local/harbor/docker-compose.yml up
            ExecStop=/usr/bin/docker-compose -f /usr/local/harbor/docker-compose.yml down

            [Install]
            WantedBy=multi-user.target

        # systemctl daemon-reload
        # systemctl restart docker   // 确保 docerk 是启动状态
        # systemctl start harbor     // harbor启动不了 一般是防火墙 docker会自动生成防火墙规则  如更改了防火墙 需要重启docker 

        # cd /usr/local/harbor       // 要在此目录 才能执行
        # docker-compose start       // 启动  注意 要进入目录执行  如启动不了可以使用有错误提示
        # docker-compose stop        // 停止
        # docker-compose pause       // 暂停
        # docker-compose unpause     // 继续
        # /usr/bin/docker-compose -f  /usr/local/harbor/docker-compose.yml up    // 如不进入目录 要加配置文件执行启动

        # http://192.168.10.13/
            admin
            Harbor12345

        用户管理 --> 创建用户
            用户名 teo
            密  码 teo@1234
        仓库管理 --> 新建目标
            提供者   Harbor
            目标名   myproject
            目标URL  http://192.168.10.13/
            访问ID   teo                              // 上创建的 用户名和密码
            访问密码  Teo@1234

        推送镜像到服务器
        # vim /etc/docker/daemon.json                 // 在其他机器上 推送 测试
            {
                "insecure-registries": ["192.168.10.13"]   // 添加 非https认证地址 如果是https不用此项 如果非80端 需加端口
            }
        # systemctl restart docker
        # docker images                  // 查看 镜像
        # docker tag nginx1:v1 192.168.10.13/test1/nginx1:v1     // 为镜像 打标签   服务器地址/仓库名字/镜像名:版本号
        # docker tag nginx1:v2 192.168.10.13/test1/nginx1:v2
        # docker login 192.168.10.13                             // 登录服务器
            teo
            Teo@1234
        # docker push 192.168.10.13/test1/nginx1:v1              // 推送镜像 可以在浏览器中看到
        # docker push 192.168.10.13/test1/nginx1:v2              // 拉取镜像 可以在网页上 查看 拉取的按钮

        注: harbor 下载地址
            git网址: https://github.com/goharbor/harbor
                    https://github.com/goharbor/harbor/releases     // 可以下载 二进制版本
                    harbor-offline-installer-v2.1.3.tgz             // 二进制包


    2. 使用 Docker 自带的 私有仓库功能创建 私有仓库   docker registry 私有仓库

        官网下载网址: https://hub.docker.com/_/registry/

        # yum install docker-registry
        # rpm -ql docker-distribution                       // 其实包名是docker-distribution 额外封装的名字docker-registry
        # vim /etc/docker-distribution/registry/config.yml  // 主配置文件
            version: 0.1
            log:
              fields:
                service: registry
            storage:
                cache:
                    layerinfo: inmemory
                filesystem:
                    rootdirectory: /var/lib/registry            // 镜像仓库的目录
            http:
                addr: :5000                                     // 默认端口是5000  应该改成80或者443
        # systemctl restart docker-distribution.service

        # docker image ls                                       // 客户端 把镜像 上传到仓库
        # docker tag nginx1:v2 192.168.10.12:5000/nginx1:v2
        # vim /etc/docker/daemon.json                           // 修改本机配置文件 
            {
                "insecure-registries": ["192.168.10.12:5000"]   // 启用不安全仓库 可以使用http协议
            }
        # systemctl restart docker
        # docker push 192.168.10.12:5000/nginx1:v2              // 推到 自建仓库

        # ls /var/lib/registry/docker/registry/v2/repositories  // 生成镜像的地址


    3. 使用Docker官方镜像仓库 建立个人仓库

        a. 登录hub.docker.com 创建个人仓库
            # docker info                        // 可以看到 镜像网址 登录信息等
            # docker login -h                

            # docker login                       // 登录 9276529937  不指仓库地址 默认为hub.docker.com
            # docker logout                      // 退出
            # docker push 9276529937/teo:latest  // 上传镜像 到个人仓库

        b. 如果使用阿里云 作为个人仓库 需要注册阿里云账号 -->  搜 容器镜像服务器 --> 创建个人仓库
            # docker login registry.cn-qingdao.aliyuncs.com  // 里面会给地址及以下地址只是演示 此密码不是登录密码是设置的密码
            # docker tag 809bfb775a7c registry.cn-qingdao.aliyuncs.com/teo/httpd:v01 // 打标签 服务器地址/用户名/仓库名:标签
            # docker push registry.cn-qingdao.aliyuncs.com/teo/httpd:v01             // 关于密码 需要设置 Registry密码





........................................................................................................................


❺. 关于Docker网络

    手动创建 两个名称空间的虚拟网卡 互相通信      // 把1个网卡 分成 两半 一个放在r1 一个放在r2

        # ip netns help                       // 查看 ip netns 帮助
        # ip netns add r1                     // 添加 名称空间r1
        # ip netns add r2
        # ip netns list                       // 查看 名称空间
        # ip netns exec r1 ifconfig -a        // 在名称空间里执行命令 只能查看到lo网卡 -a查看所有网卡 此网卡为未激活状态
        # ip link help
        # ip link add name veth1.1 type veth peer name veth1.2   // 添加网卡 veth1.1  另一半名字peer name veth1.2
        # ip link show                                           // 可以看到 新添加的 veth1.1 与veth1.2
        # ip link set dev veth1.2 netns r1                       // 把 veth1.2 移到 名称空间r1中
        # ip link show                                           // 只能看到 veth1.1
        # ip netns exec r1 ifconfig -a                           // 可以看到 veth1.2的网卡  -a查看所有网卡 此网卡为未激活状态
        # ip netns exec r1 ip link set dev veth1.2 name eth0     // 把 名称空间r1中的网卡veth1.2改名为 eth0
        # ip netns exec r1 ifconfig -a                           // 查看
        # ifconfig veth1.1 10.1.0.1/24 up                        // 激活 veth1.1
        # ifconfig
        # ip netns exec r1 ifconfig eth0 10.1.0.2/24 up          // 激活名称空间r1中的eth0网卡并配置ip地址
        # ip netns exec r1 ifconfig
        # ping 10.1.0.2
        # ip link set dev veth1.1 netns r2                       // 把veth1.1 移到 r2的名称空间
        # ip netns exec r2 ifconfig -a 
        # ip netns exec r2 ifconfig veth1.1 10.1.0.3/24 up
        # ip netns exec r2 ping 10.1.0.2

    # docker run --name t1 -it --network none --rm busybox:latest
        # ifconfig                                                   // 只有lo接口 不创建网络设备 封闭式容器
    # docker run --name t1 -it --rm busybox:latest                   // 默认 为 桥接模式
        # ifconfig                                                   // 默认网络 会有网卡              ↓ 不能通外网
    # docker run --name t1 -it --network bridge --rm busybox:latest  // 同上 一样  桥接模式  可以和当前主机及其他容器的通信
        # ifconfig
        # hostname
            46c024b2e616         // 此为容器的主机名 默认为容器的ID 可用 # docker ps 查看

    # docker run --name t1 -it --network bridge -h t1.teo.com --rm busybox:latest     // -h 指明主机名为 t1.teo.com
        # hostname
            t1.teo.com
        # cat /etc/hosts
            172.17.0.2  t1.teo.com t1            // 对自己的解析
        # cat /etc/resolv.conf
            nameserver 192.168.10.254            // DNS为 主机的 DNS

    # docker run --name t1 -it --network bridge -h t1.teo.com --dns 8.8.8.8 --rm busybox:latest
        # cat /etc/resolv.conf                   // 指定 dns

    # docker run --name t1 -it --network bridge -h t1.teo.com --dns 172.17.0.1 --dns-search ilinux.io --rm busybox:latest
        # cat /etc/resolv.conf                   // 指定 搜索域

    # docker run --name t1 -it --network bridge -h t1.teo.com --dns 172.17.0.1 --dns-search ilinux.io --add-host www.teo.com:1.1.1.1 --rm busybox:latest
        # cat /etc/hosts                         // 加 host 解析
            1.1.1.1 www.teo.com


    映射端口

        # docker run --name t1 --rm -p 80 nginx  // 启动nginx镜像 -p 要映射出去的端口 默认为tcp端口 会随机使用主机的端口映射
        # iptables -t nat -vnL                   // 查看 防火墙的 转发
            Chain DOCKER (2 references)
             pkts bytes target     prot opt in     out     source       destination         
                0     0 RETURN     all  --  docker0 *       0.0.0.0/0    0.0.0.0/0           
                0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0    0.0.0.0/0       tcp dpt:49153 to:172.17.0.2:8

        # docker container port t1                                // 查看容器端口的映射关系
            80/tcp -> 0.0.0.0:49155                               // 监听 所有ip的 49155端口上

        # curl 192.168.10.12:49153                                // 新开主机同一网段的 访问

        # docker run --name t1 --rm -p 192.168.10.12::80 nginx    // 虚拟机80端口   映射到   192.168.10.12的随机端口 
        # docker container port t1
            80/tcp -> 192.168.10.12:49153                         // 只监听在192.168.10.12 此ip上

        # docker run --name t1 --rm -p 80:80 nginx      // 不给地址 指的是 宿主机所有地址的80端口 映射 为虚拟机的80端口   
        # docker container port t1
            80/tcp -> 0.0.0.0:80
        # curl 192.168.10.12                            // 可直接访问


    联盟式容器                                           // 隔离文件  共享网络
        # docker run --name b1 -it --rm busybox                       
            # ifconfig
            # mkdir /tmp/testdir
            # ls /tmp/                                  // 会有刚创建的文件夹
            # echo "hello aaaaaa" > /tmp/index.html     // 创建测试页面
            # httpd -h /tmp/                            // 启动httpd
            # netstat -tnl                              // 80端口被监听

        # docker run --name b2 --network container:b1 -it --rm busybox    // 新窗口 启动b2容器 网络基于 容器b1
            # ifconfig                                                    // ↑ ip地址会和b1的一样 共享b1的名称空间
            # ls /tmp/                   // 没有 b1 上创建的文件夹   文件不共享
            # wget -O- -q 127.0.0.1      // 可以访问到 b1创建的测试页面   网络可以共享 相当于curl功能 因为busybox没有curl

        # docker run --name b2 --network host -it --rm busybox            // 网络基于 宿主机 创建  ip地址会和 宿主机一样
        # echo "hello container" > /tmp/index.html
        # httpd -h /tmp/
        # netstat -tnl

    修改docker0 网段
        # vim /etc/docker/daemon.json        // 修改配置文件 最后一行不能加 ","结尾 其他行必须以 "," 结尾
            {
              "bip": "10.0.0.1/16"
            }
        # systemctl restart docker

    修改docker TCP监听端口

        dockerd 守护进程 默认仅监听Unix socker格式的地址  /var/run/docker.sock  如果使用TCP套接字

        # vim /usr/lib/systemd/system/docker.service       // 修改启动文件
            ExecStart=/usr/bin/dockerd
        # systemctl daemon-reload
        # systemctl reset-failed docker.service
        # systemctl restart docker
        # vim /etc/docker/daemon.json
            "bip": "10.0.0.1/16",
            "hosts": ["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"]

        # ss -tnl                                     // 2375端口被监听
        # docker -H 192.168.10.12:2375 image ls       // 其他机器   远程 连接 执行命令

    创建 桥
        # docker network --help              // docker network 命令的参数选项
        # docker network create --help       // docker network create 命令的参数选项


        # docker network create --driver bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" mybr0
        # docker network ls
        # ifconfig                           // 会多了网卡br-53edc22a792a

        # docker run --name t2 -it --network mybr0 busybox:latest          // 基于新建的网络 创建容器
            # ifconfig                                                     // mybr0 同一网段

        # docker run --name t3 -it --network bridge busybox:latest   
           // t2 t3基于两个网卡创建的容器 只要宿主机开启核心转发 就可以通信 不能通信的原因是防火墙默认生成阻断的规则 需修改规则


    Docker 网络其他命令
        # yum install bridge-utils           // 网络查看工具 查看桥接工具
        # brctl show                         // 可看到 docker0上 桥接的网卡
        # iptables -t nat -vnL               // 会看到 原地址 172.17.0.0  不是从 docker0出去的 都做 MASQUERADE地址伪装
            Chain POSTROUTING (policy ACCEPT 222 packets, 21512 bytes)
             pkts bytes target     prot opt in     out     source               destination         
                0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0

    注:
        ①. 使用docker 需要首先开启 地址转发功能
            # vim /etc/sysctl.conf
                net.ipv4.ip_forward=1
            # sysctl -p
        ②. 报错 docker: Error response from daemon: driver failed programming external connectivity on endpoint   
            运行 # docker run --name t1 --rm -p 80 nginx 有时会报错 是由于docker启动时定义的自定义链DOCKER由于某种原因被清掉
            # systemctl restart docker        // 重启docker服务及可重新生成自定义链DOCKER 即可解决


........................................................................................................................


❻. 关于 Docker 存储
    

    volume 存储卷      // 分两种 一种为 在主机的默认路径  另一种为 执行主机的目录

    1. 创建卷 主机的默认路径
        # docker run --name t1 -it -v /data busybox      // -v 创建 卷 目录为 容器的 /data 目录 删除容器 在主机上的目录也不会没
        # docker inspect t1                              // 查看 容器的详细信息
            "Mounts": [                                  // ↓ 此路径为 主机的 物理路径
                "Source": "/var/lib/docker/volumes/20a53875f16cf53b77dd8325e239168850925ddde02977f686399272e5860d02/_data",
                "Destination": "/data",                  // 此为 容器的路径 关联了 上面的物理路径

    2. 创建卷 主机的指定路径
        # docker run --name t2 -it --rm -v /data/b2:/data busybox  // 创建卷   把主机的 /data/b2 目录 关联到 容器的 /data
        # docker inspect t2
            "Mounts": [
                    "Source": "/data/b2",         // 主机的路径     没有此路径  会自动创建   删除容器 在主机上的目录也不会没
                    "Destination": "/data",       // 容器的路径

        注: inspect 格式详解
            # docker inspect t2                    // go模板的格式 可以使用模板的方式来过滤信息
                [                                  // 中括号为  列表
                    {                              // 大括号为 映射 哈希 关联数组 json数组
                        "Id":  "....."             // 键    键值
                        "State": {                 // 内部的嵌套 其中值为 另一个 json数组 json文档   上一级 为 根
                            "Status": "running",   // 二级键 为  State.Status   键值为 running       上一级为 State


                    }
                }
            ]
        # docker inspect -f {{.Mounts}} t2         // 调用 数值
        
    3. 两个容器 共享 同一个存储卷
        # docker run --name t1 -it --rm -v /data1:/data1 busybox            
        # docker run --name t2 -it --rm -v /data1:/data1 busybox  // 和 t1 一样的 目录
        
        基础支撑的容器  infracon 

        # docker run --name d1 -it -v /data/:/data/ busybox       // 基础容器 可以不启动 存在就可以 -it 只是为了看效果
        # docker container ls -a                                  // --volumes-from 复制d1 容器的 卷
        # docker run --name nginx --network container:d1 --volumes-from d1 -it busybox    // 复制基础容器的卷 网络空间


........................................................................................................................


❼. 关于 Docker 系统限制

    docker 默认 没有限制内存 和 cpu

    内存
        物理内存 和 交换内存

        -m               可用物理内存的大小   // 可单独使用
        --memory-swap *  可用交换分区的大小   // 不可单独使用 一定要先设置物理内存的使用大小 才能使用此项设置交换分区的使用大小
            关于交换分区的设置   --memory-sqap=S     --memory=M      S一定要大于M
            1. 容器可用内存总空间为S   其中 物理内存为 M  交换分区为S-M 若S=M则无可用交换分区资源
            2. 如果--memory-swap=0  相当于未设置交换分区    未设置交换分区:如果宿主机启用了交换分区 则容器可用交换分区为 2*M
            3. 如果--memory-swap=-1 如果宿主机启用了交换分区 则容器可用所有宿主机的交换分区
            4. 在容器中 使用free命令 可以看到的交换空间并不具有其所展现出的空间的意义  就是 不准

        --memory-swappiness    使用交换分区的倾向性 0-100   0为能不用就不用  100为能用就用

    CPU
        --cpu--shares=     cpu资源共享 按比例切分当前系统上所有的cpu资源
        --cpus=            分配多少核心
        --cpuset-cpu=      指定使用哪些核心
        --cpu-period=      限制多长时间

    使用压力测试工具 限制内存 CPU                            // https://hub.docker.com/r/lorel/docker-stress-ng
        # docker pull lorel/docker-stress-ng:latest        // 容器压力测试工具

        # docker run --name t1 --rm -m 128m  lorel/docker-stress-ng stress --vm 2  // --vm 2 对内存做压力测试启动2个进程 
            -m 128m    给容器最多128m内存                                           // ↑ 默认每个进程最大内存256m
            --oom-kill-disable           // 无论使用多少内存都不会被kill掉
            --oom-score-adj 0            // -1000 - 1000 取值 越小 越不容易被kill掉

        # docker top t1                  // 可以看到 内存的使用情况  新开窗口
        # docker stats                   // 可以看到 cpu 使用情况

        # docker run --name t1 --rm --cpus 2  lorel/docker-stress-ng stress --vm 8
            --rm --cpus 2     限制cpu的核心数

        # docker run --name t1 --rm --cpuset-cpus 0,2 lorel/docker-stress-ng stress --vm 4
            --cpuset-cpus 0,2  限制cpu只能用0和2号的cpu

        # docker run --name t1 --rm --cpu-shares 1024 lorel/docker-stress-ng stress --vm 4
            --cpu-shares 1024  给cpu基础的 1份 相当于没有限制cpu

        # docker run --name t2 --rm --cpu-shares 512 lorel/docker-stress-ng stress --vm 4   // 相当于上面 2:1 的分配方式


........................................................................................................................


❽. 其他的一些关于Docker 的镜像制作


    使用 commit 制作镜像 

      使用 busybox里的httpd 制作 web服务器

        # docker run -d -it --name t1 busybox /bin/sh
        # docker container exec -it t1 /bin/sh
            # mkdir -p /data/html
            # cd /data/html
            # echo "the server is busybox server..." > index.html

        ①.基于在运行的容器 制作镜像 未指定 任何信息
            # docker container commit -p b1          // 新开窗口 制作镜像
            # docker image ls                        // 会看到 自建的镜像 仓库为空  标签为空 
                REPOSITORY               TAG             IMAGE ID       CREATED              SIZE
                <none>                   <none>          809bfb775a7c   About a minute ago   1.24MB
            # docker image tag 809bfb775a7c teo/httpd:v01      // 基于id创建仓库及标签 仓库为teo/httpd 标签为v01
            # docker image tag teo/httpd:v01 teo/httpd:v0.11   // 在打一个标签
            # docker image ls                                  // 这两个 id会一样
                REPOSITORY               TAG             IMAGE ID       CREATED          SIZE
                teo/httpd                v0.11           809bfb775a7c   10 minutes ago   1.24MB
                teo/httpd                v01             809bfb775a7c   10 minutes ago   1.24MB
            # docker image rm teo/httpd:v01                    // 删除 其中一个标签
            # docker image ls
            # docker run --name t1 -it teo/httpd:v0.11         // 运行 自建的镜像
                cat /data/html/index.html                      // 刚刚写入的 网页文件

        ②.基于在运行的容器 制作镜像 指定信息 
            # docker commit -a "teo" -c 'CMD ["/bin/httpd","-f","-h","/data/html"]' -p b1 teo/httpd:v0.2
                -a 指定作者等信息
                -c 修改原有的启动命令
                    /bin/httpd   要执行的命令
                    -f 在容器的前台执行命令  此为 httpd的选项
                    -h 指明 网页路径
                    执行的目
                -p 制作时暂停容器
                基于 b1 镜像 制作  仓库名:标签

            # docker image ls
            # docker run -d --name t2 -p 80:80 teo/httpd:v0.2    // 启动
            # docker container ls
            # curl 192.168.10.11
                # docker inspect t2                              // 如果不映射 查看docker内部ip
                # curl 172.17.0.5                                // 测试访问


    Dockerfile 制作 Nginx 镜像       基于 nginx:stable-alpine 镜像 制作 需要的nginx镜像

        # cd /data/image2/                                       // 新目录 与上面的没有关系
        # docker pull nginx:stable-alpine                        // 下载 nginx  alpine版  镜像
        # docker run --name n1 -it nginx:stable-alpine /bin/sh   // 可以运行nginx 先看一下 里面有什么目录
            # which nginx                                        // nginx 位置
                /usr/sbin/nginx
            # ls /etc/nginx/                                     // nginx 配置文件路径
        # docker container ls -a
        # docker container rm n1
        # vim Dockerfile                                         // 创建 Dockerfile
            FROM nginx:stable-alpine
            LABEL maintainer="teo <teo@teo.com>"
            ENV NGX_DOC_ROOT='/data/web/html/'
            ADD index.html ${NGX_DOC_ROOT}                 // 拷贝 主页 文件
            ADD entrypoint.sh /bin/                        // 把自定义的脚本 拷贝到 镜像里面
            CMD ["/usr/sbin/nginx","-g","daemon off;"]     // 在此 cmd 为 entrypoint的参数  详情看 注1 注2
            ENTRYPOINT ["/bin/entrypoint.sh"]              // 制作完镜像 启动镜像时的 执行  自定义脚本
        # vim entrypoint.sh                                // 创建自定义脚本  初始化一个自定义的nginx 配置文件
            #!/bin/sh
            #
            cat > /etc/nginx/conf.d/www.conf << EOF
            server
            {
                server_name $HOSTNAME;
                listen ${IP:-0.0.0.0}:${PORT:-80};
                root ${NGX_DOC_ROOT:-/data/};
            }
            EOF
            exec "$@"      // exec替代shell进程 容器里面只有/usr/sbing/nginx 唯一的一个进程  $@调用所有参数  执行cmd 传递来的参数
        # vim index.html   // 创建 自定义的主页文件
            aaaaaaaaaaaaaaaaaaa
        # docker image build -t nginx1:v1 ./                   // 制作镜像
        # docker container run --name t1 --rm -P nginx1:v1     // 启动

        # docker exec -it t1 /bin/sh                 // 新开窗口 连接到里面
            / # cat /etc/nginx/conf.d/www.conf       // 自定义配置文件
                server_name 4e30edd91e4c;
                listen 0.0.0.0:80;
                root /data/web/html/;
            / # netstat -tnl                         // 80端口被监听
            / # wget -O - -q localhost               // 相当于 curl 命令 依然是默认的页面
            / # wget -O - -q 4e30edd91e4c            // 主机名访问 可以访问到 自定义的页面
        # docker kill t1                             // 干掉

        # docker run --name t1 --rm -P -e "PORT=8080" nginx1:v1  // -e 设置环境变量 会 取代 Dockerfile文件中定义的 环境变量
        # docker exec -it t1 /bin/sh
            / # netstat -tnl                                     // 8080 被监听


    Dockerfile 部署 nginx 镜像

        # docker search nginx            // 老的网址 需要写进镜像的 可以用此配置
        # docker pull nginx:latest
        # cd /data
        # rz nginx.conf                  // 主配置文件  写进镜像
        # rz www.tar.gz                  // 网页文件目录  写进镜像
        # rz vhost.tar.gz                // 配置文件目录  写进镜像
        # rz live.tar.gz                 // SSL证书目录 写进镜像
        # vim Dockerfile
            # nginx 1.19.6
            FROM nginx:latest
            LABEL maintainer="teo <teo@teo.com>"
            ADD nginx.conf /etc/nginx/            // 可以替换掉原有的配置文件
            ADD www.tar.gz /data/
            ADD vhost.tar.gz /etc/nginx/
            ADD live.tar.gz /etc/letsencrypt/
        # docker build -t nginx:v1 ./             // 制作镜像
        # docker image ls

        # docker run --name t1 -d nginx:v1
        # docker cp t1:/etc/nginx/ /etc/
        # docker cp t1:/data/www /data/
        # docker cp t1:/var/log/nginx /var/log
        # docker rm -f t1
        # docker run -d --name t1 -p 80:80 -p 443:443 -v /data/www/:/data/www/ -v /etc/nginx/:/etc/nginx/ -v /var/log/nginx:/var/log/nginx -v /etc/letsencrypt/live/:/etc/letsencrypt/live/ nginx:v1

        # docker inspect t1    // 查看正常 运行的容器的配置
                "Mounts": [     // 主要查看 Mounts 目录 映射关系

                ],