zoukankan      html  css  js  c++  java
  • 基于Docker快速搭建LNMP环境

    TOC
    https://docs.docker.com/

    前言

    什么是Docker?

    Docker是一个开放源代码软件项目,让应用程序布署在软件容器下的工作可以自动化进行,借此在Linux操作系统上,提供一个额外的软件抽象层,以及操作系统层虚拟化的自动管理机制。Docker利用Linux核心中的资源分离机制,例如cgroups,以及Linux核心命名空间(name space),来建立独立的软件容器(containers)。这可以在单一Linux实体下运作,避免启动一个虚拟机器造成的额外负担。

    Docker VS VM

    Docker守护进程可以直接与主操作系统进行通信,为各个Docker容器分配资源;它还可以将容器与主操作系统隔离,并将各个容器互相隔离。而虚拟机VM是主操作系统Hypervisor对硬件资源进行虚拟化出独立的子操作系统,资源并不共用。

    为什么要用docker

    1、保证线下的开发环境、测试环境和线上的生产环境一致。
    2、相比于VM,启动速度快,资源利用率高,性能开销小
    3、DevOps
    4、微服务,一个服务只做好一件事
    5、自动执行设置和配置开发环境的重复任务,以便开发人员可以专注于重要的事情:构建出优秀的软件。

    Docker相关概念

    镜像Image

    Docker 镜像就是一个只读的模板。镜像可以用来创建 Docker 容器。
    Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
    镜像=操作系统+软件运行环境+用户程序
    例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。

    我们可以通过编写 Dockerfile 来创建镜像。

    容器Container

    Docker 利用容器来运行应用。
    容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
    可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
    注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层

    数据卷Volume

    数据卷让你可以不受容器生命周期影响进行数据持久化。
    使用docker的时候必须做出的思维改变是:容器应该是短暂和一次性的.

    容器启动的时候,将被分配一个随机的私有IP,其它容器可以使用这个IP地址与其进行通讯。这很重要,原因有二:一是它提供了荣期间相互通信的渠道,二是容器将共享一个本地网络。
    要开启容器间通讯,docker允许你在创建一个新容器时引用其它现存容器,在你刚创建的容器里被引用的容器将获得一个(你指定的)别名。我们就说,这两个容器链接在了一起。
    因此,如果DB容器已经在运行,我们可以创建一个web服务器容器,并在创建时引用这个DB容器,给它起一个别名,比如dbapp。在这个新建的web服务器容器里,我可以在任何时候使用主机名dbapp与DB容器进行通讯。

    仓库Repository

    仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
    仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
    最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。 国内的公开仓库包括 Docker Pool等,可以提供大陆用户更稳定快速的访问。
    当然,用户也可以在本地网络内创建一个私有仓库。
    当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。
    注:Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。

    基于Docker创建LNMP环境

    下载镜像

    https://hub.docker.com/

    docker pull bitnami/php-fpm    #下载最新php-fpm镜像,里面自带了最新版的php
    docker pull nginx                      #下载最新nginx镜像
    docker pull mysql                     #下载最新mysql镜像

    创建数据盘

    https://docs.docker.com/storage/volumes/

    image

    注:
    1、如果直接create,文件会由容器管理,否则需要mount指定目录
    2、使用mac的同学需要注意,你会发现在机子上找不到这个路径,是因为mac的docker实际是运行在虚拟机上的,所以你需要进入docker虚拟机查看
    screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty
    此时cd /var/lib/docker/volumes/learn/_data/就是创建的这个volume。
    如果觉得麻烦Mac可以跳过这步

    docker volume create learn
    我们这里直接创建数据盘,会发现实际的路径是在docker相关目录下的

    ~/Documents/code/learn » docker volume inspect learn 
    [
        {
            "CreatedAt": "2020-04-15T11:07:22Z",
            "Driver": "local",
            "Labels": {},
            "Mountpoint": "/var/lib/docker/volumes/learn/_data",
            "Name": "learn",
            "Options": {},
            "Scope": "local"
        }
    ]

    创建网络

    https://docs.docker.com/engine/reference/commandline/network_create/

    Docker有以下网络类型:
    bridge:用于独立container之间的通信
    host: 直接使用宿主机的网络,端口也使用宿主机的
    overlay:当有多个docker主机时,跨主机的container通信
    macvlan:每个container都有一个虚拟的MAC地址
    none: 禁用网络
    默认情况下,docker会创建一个桥接网络,当你创建一个新的容器执行docker run的时候,将会自动连接到这个桥接网络,你不能删除这个默认网络,但是可以创建一个新的。
    Docker在默认情况下,分别会建立一个bridge、一个host和一个none的网络:

    ~ » docker network ls
    NETWORK ID NAME DRIVER SCOPE
    a0bf815f3cb0 bridge bridge local
    836b8a7368f8 host host local
    8f2915cdc31a none null local
    
    
    docker network create --subnet=172.54.0.0/24 lnmp #创建B类划分子网络,方便配置文件中直接使用容器名称

    创建php-fpm、nginx、mysql镜像

    https://docs.docker.com/engine/reference/commandline/run/

    docker run -d --name php -v learn:/var/www --net lnmp --restart=always bitnami/php-fpm
    docker run -d --name nginx -p 80:80 -v learn:/var/www --net lnmp --restart=always nginx
    docker run -d --name mysql --restart=always -p3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --net lnmp mysql

    mac下:

    docker run -d --name php -v /Users/lixin/Documents/code/learn:/var/www --net lnmp --restart=always bitnami/php-fpm
    docker run -d --name nginx -p 80:80 -v /Users/lixin/Documents/code/learn:/var/www --net lnmp --restart=always nginx
    docker run -d --name mysql --restart=always -p3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --net lnmp mysql

    修改配置文件

    #导出文件
    docker cp default.conf nginx:/etc/nginx/conf.d/default.conf
    #导入文件
    docker cp nginx:/etc/nginx/conf.d/default.conf default.conf

    修改示例如下。

    server {
        listen 80;
        server_name localhost;
    
    
        location / {
            root /var/www;
            index index.html index.htm index.php;
        }
    
    
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root /usr/share/nginx/html;
        }
    
    
        location ~ .php$ {
            root /var/www;
            fastcgi_pass php:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }

    然后重启nginx
    docker restart nginx

    创建测试页

    <?php
    phpinfo();
    ?>

    linux下:
    将文件移动到数据卷目录下(web根目录就在这个目录下)
    mv index.php /var/lib/docker/volumes/webpage/_data/

    mac下:
    直接在mount的目录下创建文件即可。

    然后访问localhost

    连接MySQL

    创建测试文件

    <?php
    $link = mysqli_connect('mysql', 'root', '123456');
    if (!$link) {
     die('Could not connect: ' . mysqli_connect_error());
    }
    echo 'Connected successfully';
    mysqli_close($link);
    ?>

    访问之后你会发现报错:【Could not connect: The server requested authentication method unknown to the client】
    这是因为MySQL8.0之后调整了认证加密插件,而php的连接库还不支持(参考这里还有这里)。

    解决方案:
    1、进入容器
    2、登录mysql
    3、执行ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY '123456'; 用原插件重新设置一次密码。

    ~ » docker exec -it mysql /bin/sh;exit
    # mysql -u root -p
    Enter password:
    Welcome to the MySQL monitor. Commands end with ; or g.
    Your MySQL connection id is 10
    Server version: 8.0.19 MySQL Community Server - GPL
    
    
    Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
    
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    
    Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
    
    
    mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY '123456';
    Query OK, 0 rows affected (0.01 sec)
    
    
    mysql>

    刷新:Connected successfully

    Docker-Compose创建LNMP环境

    Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。
    Docker-Compose将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)。Docker-Compose运行目录下的所有文件(docker-compose.yml,extends文件或环境变量文件等)组成一个工程,若无特殊指定工程名即为当前目录名。一个工程当中可包含多个服务,每个服务中定义了容器运行的镜像,参数,依赖。一个服务当中可包括多个容器实例,Docker-Compose并没有解决负载均衡的问题,因此需要借助其它工具实现服务发现及负载均衡。
    Docker-Compose的工程配置文件默认为docker-compose.yml,可通过环境变量COMPOSE_FILE或-f参数自定义配置文件,其定义了多个有依赖关系的服务及每个服务运行的容器。
    使用一个Dockerfile模板文件,可以让用户很方便的定义一个单独的应用容器。在工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个Web项目,除了Web服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。
    Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
    Docker-Compose项目由Python编写,调用Docker服务提供的API来对容器进行管理。因此,只要所操作的平台支持Docker API,就可以在其上利用Compose来进行编排管理。

    https://docs.docker.com/compose/
    https://docs.docker.com/compose/install/
    https://docs.docker.com/compose/gettingstarted/
    https://docs.docker.com/compose/compose-file/
    注:
    1、mac的桌面版Docker自带compose,所以不需要安装了。

    2、也可以考虑用docker stack

    如果需要经常到一个新的机子上搭建环境,像上面那样每次都一个一个创建就很麻烦了,这个时候可以使用docker-compose,通过YAML来定义软件服务,最后只需要一个命令,就能创建并允许所有定义到的服务。
    通常使用compse基于下列三个步骤:

    • 基于dockerfile定义好程序的运行环境,这样你可以在任何情况下复用。(如果不需要build,这个步骤可以忽略,直接用现成的image)
    • 基于docker-compose.yml来定义服务,这样可以在隔离的环境下同时运行。
    • 运行docker-compose up 来创建并运行整个程序。
      可以用于开发环境、自动化测试、单机部署。

    示例文件如下:

    version: '3'
    services:
      php:
        container_name: php
        image: "bitnami/php-fpm"
        networks:
          - lnmp
        volumes:
           - /Users/lixin/Documents/code/learn:/var/www
        restart: always
      nginx:
        container_name: nginx
        image: "nginx"
        ports:
          - "80:80"
        volumes:
           - /Users/lixin/Documents/code/learn:/var/www
        networks:
          - lnmp
        restart: always
      mysql:
        container_name: mysql
        image: "mysql"
        ports:
          - "3306:3306"
        networks:
          - lnmp
        restart: always
        environment:
          MYSQL_ROOT_PASSWORD: "123456"
    networks:
      lnmp:
        ipam:
          driver: default
          config:
            - subnet: "172.54.0.0/24"

    然后保存为docker-compose.yml将文件放置于一个专门存放的compose相关的目录里执行命令

    ~/Documents/code/learn » docker-compose up -d
    Starting php ... done
    Starting nginx ... done
    Starting mysql ... done

    注:基于compose创建的容器会放在以docker-compose.yml的目录为名称的容器组下面

    容器中nginx不记录日志的问题

    使用过程中你会发现,即使nginx的conf设置了访问日志,错误日志,但是却没有写入到相应的文件里。
    这是因为nginx官方默认已经设置了直接输出到Docker的日志收集器里。

    FROM debian:jessie
    
    
    MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com"
    
    
    ENV NGINX_VERSION 1.11.5-1~jessie
    
    
    RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 
     && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list 
     && apt-get update 
     && apt-get install --no-install-recommends --no-install-suggests -y 
          ca-certificates 
          nginx=${NGINX_VERSION} 
          nginx-module-xslt 
          nginx-module-geoip 
          nginx-module-image-filter 
          nginx-module-perl 
          nginx-module-njs 
          gettext-base 
     && rm -rf /var/lib/apt/lists/*
    
    
    # forward request and error logs to docker log collector
    RUN ln -sf /dev/stdout /var/log/nginx/access.log 
     && ln -sf /dev/stderr /var/log/nginx/error.log
    
    
    EXPOSE 80 443
    
    
    CMD ["nginx", "-g", "daemon off;"]

    注:The official nginx image creates a symbolic link from /var/log/nginx/access.log to /dev/stdout, and creates another symbolic link from /var/log/nginx/error.log to /dev/stderr, overwriting the log files and causing logs to be sent to the relevant special device instead. See the Dockerfile.

  • 相关阅读:
    LeetCode 654. 最大二叉树
    LeetCode 617. 合并二叉树
    LeetCode 234. 回文链表
    LeetCode 328. 奇偶链表
    LeetCode 24. 两两交换链表中的节点
    LeetCode 21. 合并两个有序链表
    LeetCode 876. 链表的中间结点
    顺序表的定义及其相关基本操作
    LeetCode 206. 反转链表
    LeetCode 111. 二叉树的最小深度
  • 原文地址:https://www.cnblogs.com/leestar54/p/12707648.html
Copyright © 2011-2022 走看看