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 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 5

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

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

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

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

这里 WORKDIR /data 是本机目录吗


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

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

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

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

4年前 评论