docker 入门讲解 - 构建本地环境

docker入门讲解

最近公司在提倡使用 docker,之前只是简单了解了一下基础语法,在本机上搭建了一个 php 容器凑合着用,周末在家没事所以准备把这块再继续加深一下理解,用比较通俗的语言来阐述一下自己的理解。本篇文章适合小白及入门阅读使用,目的是让对 docker 不熟悉甚至没有用过的人能够有一个直观的理解。

1.docker是什么

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

docker 官方的解释,看起来有点像我们之前用过的虚拟机,但是和虚拟机还是有些区别的:

  • 虚拟机模拟的是整台机器包括硬件,每台虚拟机都有自己的操作系统,虚拟机一旦开启预分配给他的资源将全部占用。
  • 容器与我们的宿主机共享硬件资源及操作系统,可以实现资源动态分配,容器包含应用及依赖包,而且与其他容器共享内核。容器在宿主机操作系统中,在用户空间以分离的进程运行。

这是引用网上的对容器和虚拟机区别的一些概述,以我个人的理解来看,容器比虚拟机可以管理的粒度更小,更适合我们作为日常开发及应用的部署,而且比虚拟机更轻,对宿主机硬件的要求也更低。

2.docker能用来做什么

如果站在php开发的角度来看的话,我相信大部分人都对更换开发机,部署服务器运行环境感到头大,那意味着你将要耗费大量的时间,对应用进行下载、安装以及配置,一不小心几个小时就过去了,尤其是如果在本地调试需要切换不同PHP版本进行程序调试。当然你可以选择使用集成环境来进行部署,不过安装之后的自定义配置、扩展的安装还是免不了。(很久之前本地开发是使用phpstudy的,确实是很方便,不知道现在是不是有更好的工具)

那么docker可以很好的解决这个问题,我们可以把自己已经构建好的一套运行环境打包成镜像,下次再使用的时候直接下载镜像进行安装即可使用,而且可以安装不同的版本,满足我们对任意环境的组合要求,看这个样子是不是有点像我们安装操作系统时直接从镜像安装一样?差不多的道理, 只不过docker可以将镜像封装的粒度更细,可以将一个php、nginx或任意你想要的应用封装起来,这样我们在使用的时候选择性就更多一些。

3.基础语法介绍

我们先介绍几个简单的命令:

  • docker pull -- 从远程仓库将镜像下载至本地
  • docker run -- 运行一个容器
  • docker exec -- 对镜像进行操作,常用的就是我们进入到镜像中进行配置(有点像我们远程登录一个linux服务器)

上面三条指令就可以帮助我们搭建一个简单容器进行使用,下面是几条常用的常看容器的命令:

  • docker images -- 常看本地镜像
  • docker ps -- 查看容器,默认只查看已启动的,加入 "-a" 参数可以查看所有
  • docker start|stop|rm|rmi -- 容器的相关操作,分别对应: 开启|停止|删除容器|删除镜像

4.一个简单的例子

4.1下载一份ubuntu的最新镜像

docker pull ubuntu

4.2运行容器指定镜像

docker run ubuntu echo 'Hello'

可以看到命令行下方打印出‘Hello’字样,然后我们使用docker ps命令查看并没有我们刚才的那个容器,这是因为容器在执行完 echo 命令后没有其他的可执行命令后就会退出,这怎么行?我们使用容器主要就是想让他保持运行,所以我们需要想个办法让容器始终保持运行

4.3让容器始终保持运行

docker run -itd --name test-ubuntu ubuntu

参数说明:

  • t - 让docker分配一个伪终端并绑定到容器的标准输入上
  • i - 让容器的标准输入保持打开
  • d - 让容器后台运行
  • name - 给容器命名,否则就是系统随机生成的一个名字,不好记,这里我们给他命名叫:test-ubuntu

it 参数可以让容器始终保持一个伪终端等待用户的输入,但是因为加了d参数,使容器进入后台执行了,所以不会有人输入到容器,这样容器就一直保持运行了。可以使用docker ps命令查看一下哦。

4.4进入容器

docker exec -it test-ubuntu /bin/bash

说明:使用exec指令,在容器名称后的参数表示进入容器后执行的命令,这里我们使用base命令处理器,以达到我们和容器交互的效果。

这样我们就进入容器中了,可以看到基础的镜像中很多的命令都不存在,需要我们一一进行安装,我这里使用的是ubuntu,所以可以执行apt-get update && apt-get install xxx 来进行安装。

到这里docker的基础使用我们已经介绍完了,下面我们来实战一下,创建一个我们平时使用的php容器。

5.使用docker搭建一个php-fpm容器

5.1首先我们从远程仓库下载一份php-fpm镜像

docker pull php:7.3.5-fpm

说明:冒号后面跟着镜像的tag,不写默认就是最新的,但可能不是fpm,我这里选择的是7.3.5的php-fpm版本

5.2运行一个容器

docker run -itd -p 9001:9000 -v /Users/admin/Site/php7.3.5:/data --name php-test php:7.3.5-fpm

参数说明:

  • p - 格式:-p [宿主机端口]:[容器端口]指定宿主机与容器之间的端口映射,我这里使用的是9001对应容器的9000端口
  • v - 格式:-v [宿主机目录]:[容器目录]挂载一个宿主机的目录,这里我挂载的是php代码,这样我们在宿主机修改php代码时,就可以同步到容器中了。其实php-fpm的配置文件相关的也可以使用-v参数来挂载,省的每次修改都进入容器里改了,这个示例我没加,感兴趣的同学可以下去自己加一下。

这样我们就创建了一个php-7.3.5版本的容器

5.3进入容器

docker exec -it php-test /bin/bash

进入容器后可以使用php -v来查看php版本,如果需要安装扩展可以使用pecl install redis 来进行安装(这里只是举例redis,只是这样会安装失败,需提前安装所需依赖,你们自己想办法 [滑稽脸])。

因为我们下载的是php镜像,所以一些此镜像启动后会默认启动php-fpm作为1号进程,也就是说如果我们杀死php-fpm进程,此容器就会关闭。

5.4使用nginx关联容器的php-fpm使用

新建一个测试站点,配置文件如下(路径改成你自己的,主要关注fpm那里的设置即可):

server {
    # 监听端口
    listen       80;

    # 域名设定
    server_name  www.dockertest.com;

    root /Users/admin/Site/php7.3.5/; # 该项要修改为你准备存放相关网页的路径,如果存在fast-cgi的root字段,这里貌似就没效果了

    location / {

    index index.php index.html;

    # 打开目录浏览功能,可以列出整个目录

    autoindex on;

    }

    #proxy the php scripts to php-fpm

    location ~ \.php$ {
    # fastcgi配置

    # 指定是否传递4xx和5xx错误信息到客户端

    fastcgi_intercept_errors on;

    # 指定FastCGI服务器监听端口与地址,可以是本机或者其它,这里是重点,需要指定php-fpm容器的端口和根目录
    fastcgi_pass   127.0.0.1:9001;
    root /data;
    fastcgi_index index.php;
    include  fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

}

这样,我们运行www.dockertest.com时,就可以访问到php-test容器中/data/index.php文件了。
用一张图来表示容器在宿主机里的状态:

image

6.进阶使用:Dockerfile

好了,到了这里我们已经了解到如何去搭建一个容器以及容器的基本使用了,可是有一个问题,那就是虽然我们的容器运行起来了,但是想要真正的去深度使用他还需要安装各种常用命令以及依赖,比如vim指令、php的各种依赖等,因为仓库的镜像资源是不包含这些指令的,所以还需要我们自己来处理,那么有没有什么方法可以不用每次构建容器都去做这些重复的配置呢?当然有,就是Dockerfile。

Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。

说白了,其实就是将我们想要构建的容器中使用到的各种应用和依赖进行一个打包,让程序自动的来运行。写好Dockerfile后使用build指令即可。

docker build -t php7.3.5 .

其中 php7.3.5 是构建完成之后容器的名称, 「.」表示运行当前目录的Dockerfile,所以命名不要写错,必须是「Dockerfile」

7.Dockerfile参数解释

Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,’#’ 为 Dockerfile 中的注释。

Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以#字符开头则被视为注释。可以在Docker文件中使用RUN,CMD,FROM,EXPOSE,ENV等指令。

在这里列出了一些常用的指令。

字段名称 解释
FROM 指定基础镜像,必须为第一个命令
MAINTAINER 维护者信息
RUN 构建镜像时执行的命令
ADD 将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget
COPY 功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
CMD 构建容器后调用,也就是在容器启动时才进行调用。
ENTRYPOINT 配置容器,使其可执行化。类似于CMD,但如果使用docker run 配合执行指令时,会覆盖CMD的命令,ENTRYPOINT的不会被覆盖,始终会执行
EXPOSE 指定于外界交互的端口
VOLUME 用于指定持久化目录,注意这个和docker run -v参数不一样,这里是标注此容器中哪个目录是作为挂载卷存在的,这样别的容器可以配合使用--volumes-from [containerId] 就可以将挂载的卷同步过来了
WORKDIR 工作目录,类似于cd命令

8.使用Dockerfile搭建php-fpm

这里就不多写了,直接呈上php-fpm的Dockerfile文件,仅供大家参考:

FROM php:7.3.5-fpm
MAINTAINER liyan

#安装环境系统命令
RUN apt-get update && apt-get install -y \
vim \
libssl-dev

#安装PHP扩展
RUN pecl install igbinary \
redis-4.0.2 \
swoole

#配置php.ini
RUN cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini && \
ln -s /usr/local/etc/php/php.ini /etc/php.ini && \
echo "extension=igbinary.so\nextension=redis.so\nextension=swoole.so" >> /etc/php.ini

EXPOSE 9300
VOLUME ["/data"]
WORKDIR /data

9.使用Dockerfile搭建nginx+php环境

这里将nginx+php都放在同一个容器中了,其实按理说应该独立开来更灵活,一个nginx可以对应N个php,我也是闲的蛋疼,都弄一块用supervisor来管理。感兴趣的同学也可以玩玩。

FROM ubuntu
MAINTAINER liyan

#创建用户
RUN useradd www

#安装依赖
RUN apt-get update && \
apt-get install -y \
vim \
make \
gcc \
g++ \
openssl \
curl \
libcurl4-openssl-dev \
libbz2-dev \
libxml2-dev \
libjpeg-dev \
libpng-dev \
libfreetype6-dev \
libzip-dev \
libssl-dev \
unzip \
supervisor

#拷贝相关依赖
ADD nginx-1.16.1.tar.gz /usr/local/src
ADD php-7.3.11.tar.xz /usr/local/src
ADD zlib-1.2.11.tar.gz /usr/local/src
ADD pcre-8.43.tar /usr/local/src
COPY supervisord.conf /etc/supervisor/
COPY conf.d /etc/supervisor/conf.d/

#安装nginx依赖
RUN cd /usr/local/src/zlib-1.2.11 && ./configure && make && make install

#安装nginx
RUN cd /usr/local/src/nginx-1.16.1 && \
./configure --with-pcre=/usr/local/src/pcre-8.43 && \
make && make install && \
ln -s /usr/local/nginx/sbin/nginx /usr/local/bin/

#安装PHP
RUN cd /usr/local/src/php-7.3.11 && ./configure \
--prefix=/usr/local/php \
--with-config-file-path=/usr/local/php/etc \
--enable-fpm \
--with-fpm-user=www \
--with-fpm-group=www \
--with-mysqli \
--with-pdo-mysql \
--with-iconv-dir \
--with-freetype-dir \
--with-jpeg-dir \
--with-png-dir \
--with-zlib \
--with-libxml-dir=/usr \
--enable-xml \
--disable-rpath \
--enable-bcmath \
--enable-shmop \
--enable-sysvsem \
--enable-inline-optimization \
--with-curl \
--enable-mbregex \
--enable-mbstring \
--enable-ftp \
--with-gd \
--with-openssl \
--with-mhash \
--enable-pcntl \
--enable-sockets \
--with-xmlrpc \
--enable-zip \
--enable-soap \
--without-pear \
--with-gettext \
--disable-fileinfo \
--enable-maintainer-zts && \
make && make install &&\
ln -s /usr/local/php/sbin/php-fpm /usr/local/bin/

EXPOSE 80
VOLUME ["/data"]
WORKDIR /data
ENTRYPOINT ["supervisord", "-nc", "/etc/supervisor/supervisord.conf"]
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 1年前 自动加精
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 5

请问楼主 如何在 docker 或 laradock 中通过 ssh key 去和 github 通信呢?

1年前 评论
839891627 1年前
ligkwww (楼主) 1年前

赞~
这两天刚好我也折腾了下,用 docker-compose 编排了下,很简单的 dnmp 环境
https://github.com/839891627/docker-lnmp

1年前 评论
ligkwww (楼主) 1年前

这里WORKDIR /data是本机目录吗


EXPOSE 9300
VOLUME ["/data"]
WORKDIR /data
1年前 评论
ligkwww (楼主) 1年前

请问一下,像php composer 和 laravel的aritsan的相关命令,要在哪里运行?进入容器吗?

1年前 评论
ligkwww (楼主) 1年前
颠倒的玉石

docker pull php:7.3.5-fpm第一步就卡住了。提示超时。但是我google速度还可以呀。小飞机关了也是这个提示

9个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!