查看: 1092|回复: 0

[PHP代码] Docker:说爱你不容易

发表于 2017-10-12 08:00:04
太阳http代理AD

docker 对于很多程序猿来说,一点都不陌生,毕竟它是一个轻量级的部署神器。

也许,也有很多童鞋和我一样,只听说过,却没有真正的实践过 docker。那么,现在一起走进 docker 的世界。

什么是 Docker? Docker 概念

Docker is an open-source project that automates the deployment of applications inside software containers, by providing an additional layer of abstraction and automation of operating-system-level virtualization on Linux. Docker uses the resource isolation features of the Linux kernel such as cgroups and kernel namespaces, and a union-capable filesystem such as aufs and others to allow independent “containers” to run within a single Linux instance, avoiding the overhead of starting and maintaining virtual machines.

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

——摘自维基百科

Docker 和虚拟机(VM)的区别

一张图概括vm和docker的架构区别。具体的可以查看 知乎 - docker容器与虚拟机有什么区别?

总之明确一点, Docker 不是虚拟机

Docker 的应用场景 Web 应用的自动化打包和发布。 自动化测试和持续集成、发布。 在服务型环境中部署和调整数据库或其他的后台应用。 为什么要用 Docker? Docker 的优点

Docker automates the repetitive tasks of setting up and configuring development environments so that developers can focus on what matters: building great software.

Docker自动执行设置和配置开发环境的重复任务,以便开发人员可以专注于重要的事情:构建出优秀的软件。

Developers using Docker don’t have to install and configure complex databases nor worry about switching between incompatible language toolchain versions.

使用Docker的开发人员不必安装和配置复杂的数据库,也不用担心在不兼容版本之间切换。

简化配置 代码流水线(Code Pipeline)管理 提高开发效率 隔离应用 整合服务器 调试能力Docker 多租户环境 快速部署

-- 来源于 DockOne.io - 八个Docker的真实应用场景

获取 Docker 安装 官方安装。 传送门 通过阿里云镜像仓库安装

先登录 阿里云 - 开发者平台,登录后进入管理中心,点击管理中心中的 Docker Hub 镜像站点。

通过 DaoCloud 安装。 传送门 Docker 加速

目前国内比较多人用的加速器有 DaoCloud 和 阿里云。

阿里云

先登录 阿里云 - 开发者平台,登录后进入管理中心,点击管理中心中的 Docker Hub 镜像站点。

可以看到控制台中的专属加速器。

DaoCloud

  1. 登录后打开 [DaoCloud - 加速器](https://www.daocloud.io/mirror#accelerator-doc)即可看到配置 docker 加速器的脚本,拷贝代码运行即可。
复制代码
非root用户使用 docker

创建docker组: sudo groupadd docker

将当前用户加入docker组: sudo gpasswd -a ${USER} docker

重新启动docker服务:sudo systemctl restart docker

当前用户退出系统重新登陆即可。

认识 Docker 查看Docker安装情况

Docker 安装之后,可以使用 docker -v 查看docker 版本。

  1. {17-09-19 10:59}Leung:~ lynnleung% docker -v
  2. Docker version 17.06.2-ce, build cec0b72
复制代码

启动第一个docker: hello-world 。

  1. {17-09-19 11:00}Leung:~ lynnleung% docker run hello-world
  2. Unable to find image 'hello-world:latest' locally
  3. latest: Pulling from library/hello-world
  4. 5b0f327be733: Pull complete
  5. Digest: sha256:1f19634d26995c320618d94e6f29c09c6589d5df3c063287a00e6de8458f8242
  6. Status: Downloaded newer image for hello-world:latest
  7. Hello from Docker!
  8. This message shows that your installation appears to be working correctly.
  9. To generate this message, Docker took the following steps:
  10. 1. The Docker client contacted the Docker daemon.
  11. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
  12. 3. The Docker daemon created a new container from that image which runs the
  13. executable that produces the output you are currently reading.
  14. 4. The Docker daemon streamed that output to the Docker client, which sent it
  15. to your terminal.
  16. To try something more ambitious, you can run an Ubuntu container with:
  17. $ docker run -it ubuntu bash
  18. Share images, automate workflows, and more with a free Docker ID:
  19. https://cloud.docker.com/
  20. For more examples and ideas, visit:
  21. https://docs.docker.com/engine/userguide/
复制代码
Docker常用命令 pull

作用:从镜像仓库中拉取或者更新指定镜像

语法: docker pull [OPTIONS] NAME[:TAG|@DIGEST]

options:

-a:拉取所有tagged镜像 --disable-content-trust :忽略镜像的校验,默认开启

TAG 默认为 latest,即拉取仓库最新的镜像。具体的tag值可以去官方hub中查看。

举个栗子,拉取nginx镜像,未指定tag时,默认拉取最新版本(在 Docker Hub - Nginx镜像首页可以看到,最新的nginx版本为 1.13.5):

  1. {17-09-19 10:57}Leung:~ lynnleung% docker pull nginx
  2. Using default tag: latest
  3. latest: Pulling from library/nginx
  4. afeb2bfd31c0: Pull complete
  5. 7ff5d10493db: Pull complete
  6. d2562f1ae1d0: Pull complete
  7. Digest: sha256:aa1c5b5f864508ef5ad472c45c8d3b6ba34e5c0fb34aaea24acf4b0cee33187e
  8. Status: Downloaded newer image for nginx:latest
复制代码

先把镜像拉取下来,待会就可以直接使用。

run

作用:创建一个新的容器,并运行一个命令

语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

常用的options:

-a stdin:指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项 -d: 后台运行容器,并返回容器ID -i: 以交互模式运行容器,通常与 -t 同时使用 -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用 --name="my-nginx": 为容器指定一个名称 -h "hostname;": 指定容器的hostname -e username="ritchie": 设置环境变量 --link=[]: 添加链接到另一个容器 --expose=[]: 开放一个端口或一组端口 -p hostport:containerport:指定容器暴露的端口对应宿主机的端口 -P:暴露容器端口对应宿主机的随机端口 -v :给容器挂载存储卷,挂载到容器的某个目录

举个栗子,运行一个nginx:

  1. {17-09-19 11:32}Leung:~ lynnleung% docker run -P -d nginx
  2. 21ad408c79947d1cbee7540b1ae1586987acfc4bb6b09b6339b02879c70aeb2e
  3. {17-09-19 11:32}Leung:~ lynnleung% docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 21ad408c7994 nginx "nginx -g 'daemon ..." 2 seconds ago Up 1 second 0.0.0.0:32768->80/tcp hopeful_clarke
  6. bd8dc013d734 hello-world "/hello" 31 minutes ago Exited (0) 31 minutes ago clever_bohr
复制代码

可以看到 PORTS,容器中的 80 端口对应了宿主机中的 32768 端口,此时访问 http://localhost:32768 即可看到nginx的默认页面。

如果在虚拟机中运行 docker run -d -p 80:80 nginx 访问虚拟机的地址 http://10.211.55.9,同样可以打开nginx的默认页面。

  1. leung@ubuntu:~$ docker run -d -p 80:80 nginx
  2. 8b15325246d29c7b6f50cd3290c7a91fdf4b7d78240779720a2abdc64555ab45
  3. leung@ubuntu:~$ docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 8b15325246d2 nginx "nginx -g 'daemon ..." 18 hours ago Up 18 hours 0.0.0.0:80->80/tcp flamboyant_mayer
复制代码
start/stop/restart

作用:

docker start :启动一个或多少已经被停止的容器

docker stop :停止一个运行中的容器

docker restart :重启容器

语法:

  1. docker start [OPTIONS] CONTAINER [CONTAINER...]
  2. docker stop [OPTIONS] CONTAINER [CONTAINER...]
  3. docker restart [OPTIONS] CONTAINER [CONTAINER...]
复制代码

举个栗子,停止虚拟机中的nginx:

  1. leung@ubuntu:~$ docker stop flamboyant_mayer
  2. flamboyant_mayer
  3. leung@ubuntu:~$ docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 8b15325246d2 nginx "nginx -g 'daemon ..." 18 hours ago Exited (0) 3 seconds ago flamboyant_mayer
复制代码

此时再访问虚拟机ip已经是不能访问了。

再运行 docker start flamboyant_mayer可以再次启动nginx。

exec

作用:在运行的容器中执行命令

语法:docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

options:

-d :分离模式: 在后台运行 -i :即使没有附加也保持STDIN 打开 -t :分配一个伪终端

举个例子,进入虚拟机中的nginx容器查看nginx的版本和已安装模块:

  1. leung@ubuntu:~$ docker exec -it flamboyant_mayer nginx -v
  2. nginx version: nginx/1.13.5
  3. leung@ubuntu:~$ docker exec -i -t flamboyant_mayer /bin/bash
  4. root@8b15325246d2:/# nginx -V
  5. nginx version: nginx/1.13.5
  6. built by gcc 6.3.0 20170516 (Debian 6.3.0-18)
  7. built with OpenSSL 1.1.0f 25 May 2017
  8. TLS SNI support enabled
  9. configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fdebug-prefix-map=/data/builder/debuild/nginx-1.13.5/debian/debuild-base/nginx-1.13.5=. -specs=/usr/share/dpkg/no-pie-compile.specs -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-specs=/usr/share/dpkg/no-pie-link.specs -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'
  10. root@8b15325246d2:/#
复制代码

可以看到,最新版的nginx容器确实是 1.13.5 版本,并且安装了大部分常用的模块。

create

作用: 创建一个新的容器但是不启动它

语法: docker create [OPTIONS] IMAGE [COMMAND] [ARG...] 语法同 run

举个栗子:

  1. leung@ubuntu:~$ docker create -p 8888:80 --name create_nginx nginx
  2. ac3eca0321b872109b10444b4080b45f2b13333b8c265b4ec77fff05fc25ff61
  3. leung@ubuntu:~$ docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. ac3eca0321b8 nginx "nginx -g 'daemon ..." 6 seconds ago Created create_nginx
  6. 8b15325246d2 nginx "nginx -g 'daemon ..." 18 hours ago Up 10 minutes 0.0.0.0:80->80/tcp flamboyant_mayer
  7. leung@ubuntu:~$ docker start create_nginx
  8. create_nginx
复制代码

运行 start 命令后,即可访问虚拟机的 8888 端口。

build

作用: 根据 Dockerfile 构建镜像。

语法: docker build [OPTIONS] PATH | URL | -

常用的 options:

-f :指定要使用的Dockerfile路径。 --force-rm :设置镜像过程中删除中间容器。 -q :安静模式,成功后只输出镜像ID。 --no-cache :创建镜像的过程不使用缓存。 --rm :设置镜像成功后删除中间容器。 ps

作用: 列出容器

语法: create

options:

-a :显示所有的容器,包括未运行的 -f :根据条件过滤显示的内容 --format :指定返回值的模板文件 -l :显示最近创建的容器 -n :列出最近创建的n个容器 --no-trunc :不截断输出 -q :静默模式,只显示容器编号 -s :显示总的文件大小
  1. leung@ubuntu:~$ docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 8b15325246d2 nginx "nginx -g 'daemon ..." 18 hours ago Up 8 minutes 0.0.0.0:80->80/tcp flamboyant_mayer
  4. leung@ubuntu:~$ docker ps -q
  5. 8b15325246d2
  6. leung@ubuntu:~$ docker ps -s
  7. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
  8. 8b15325246d2 nginx "nginx -g 'daemon ..." 18 hours ago Up 8 minutes 0.0.0.0:80->80/tcp flamboyant_mayer 16B (virtual 108MB)
  9. leung@ubuntu:~$ docker ps -a
  10. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  11. ac3eca0321b8 nginx "nginx -g 'daemon ..." 6 seconds ago Created create_nginx
  12. 8b15325246d2 nginx "nginx -g 'daemon ..." 18 hours ago Up 10 minutes 0.0.0.0:80->80/tcp flamboyant_mayer
复制代码
port

作用: 列出指定的容器的端口映射,或者查找将PRIVATE_PORT NAT到面向公众的端口。

语法: docker port [OPTIONS] CONTAINER [PRIVATE_PORT[/PROTO]]

栗子:

  1. leung@ubuntu:~$ docker port flamboyant_mayer
  2. 80/tcp -> 0.0.0.0:80
复制代码
top

作用: 查看容器中运行的进程信息,支持 ps 命令参数。

语法: docker top [OPTIONS] CONTAINER [ps OPTIONS]

栗子:

  1. leung@ubuntu:~$ docker top flamboyant_mayer
  2. UID PID PPID C STIME TTY TIME CMD
  3. root 1999 1981 0 11:50 ? 00:00:00 nginx: master process nginx -g daemon off;
  4. systemd+ 2028 1999 0 11:50 ? 00:00:00 nginx: worker process
复制代码
images

作用: 列出本地镜像

语法: docker images [OPTIONS] [REPOSITORY[:TAG]]

常用的options:

-a :列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层) -f :显示满足条件的镜像 -q :只显示镜像ID
  1. leung@ubuntu:~$ docker images -a
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. nginx latest 66216d141be6 10 days ago 108MB
复制代码
rm/rmi

用法: rm 用于删除一个或多个容器,rmi 用于删除一个或多个本地镜像。

语法:

rm: docker rm [OPTIONS] CONTAINER [CONTAINER...]

rm 的options:

-f :通过SIGKILL信号强制删除一个运行中的容器 -l :移除容器间的网络连接,而非容器本身 -v:-v 删除与容器关联的卷

rmi: docker rmi [OPTIONS] IMAGE [IMAGE...]

rmi 的options:

-f :强制删除 --no-prune :不移除该镜像的过程镜像,默认移除 tag

作用: 标记本地镜像,将其归入某一仓库。

语法: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]

要注意这里的 username 指的是你注册docker hub后,在hub上的唯一标识符,也是登录的 username。

举个栗子:docker tag nginx leungjz/nginx

push

作用: 将本地的镜像上传到镜像仓库,要先登陆到镜像仓库

Linux登录仓库的方法是: 运行 docker login 命令,然后输入dockerhub的登录名和密码即可,登录名不是邮箱。

Mac 登录仓库为点击状态栏上的小鲸鱼,在下拉栏中选择 Sign in 登录即可。

  1. {17-09-19 14:28}Leung:~ lynnleung% docker login
  2. Login with your Docker ID to push and pull images from Docker Hub. If you don‘t have a Docker ID, head over to https://hub.docker.com to create one.
  3. Username: leungjz
  4. Password:
  5. Login Succeeded
复制代码

语法: docker push [OPTIONS] NAME[:TAG]

options:

--disable-content-trust :忽略镜像的校验,默认开启

在push前,需要标记本地某个镜像,举个栗子(Mounted 那里应为是基于我的测试账号中tag过来。):

  1. {17-09-19 14:32}Leung:~ lynnleung% docker tag nginx leungjz/nginx
  2. {17-09-19 14:33}Leung:~ lynnleung% docker push leungjz/nginx
  3. The push refers to a repository [docker.io/leungjz/nginx]
  4. 110566462efa: Mounted from buct132/nginx
  5. 305e2b6ef454: Mounted from buct132/nginx
  6. 24e065a5f328: Mounted from buct132/nginx
  7. latest: digest: sha256:d8565c25b654da69bc9b837a0dee713c988f0276e90564aa8fd12ebf4c2ff11e size: 948
复制代码
commit

作用: 从容器创建一个新镜像。

语法: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

options:

-a :提交的镜像作者 -c :使用Dockerfile指令来创建镜像 -m :提交时的说明文字 -p :在commit时,将容器暂停

举个栗子:

  1. {17-09-19 14:48}Leung:~ lynnleung% docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 6b06e2bb098e nginx "nginx -g 'daemon ..." 38 minutes ago Up 38 minutes 10.211.55.2:80->80/tcp nginx
  4. {17-09-19 14:48}Leung:~ lynnleung% docker commit -a "leungjz" -m "my nginx" 6b06 leungjz/nginx
  5. sha256:3b4cb2b72b78be5da995e42ad051cbf0c73fd62fd437ac56469d8ee8f488b4c6
  6. {17-09-19 14:49}Leung:~ lynnleung% docker images
  7. REPOSITORY TAG IMAGE ID CREATED SIZE
  8. leungjz/nginx latest 3b4cb2b72b78 6 seconds ago 108MB
  9. nginx latest da5939581ac8 5 days ago 108MB
  10. hello-world latest 05a3bd381fc2 6 days ago 1.84kB
  11. {17-09-19 14:49}Leung:~ lynnleung% docker push leungjz/nginx
  12. The push refers to a repository [docker.io/leungjz/nginx]
  13. a13795f76641: Pushed
  14. 110566462efa: Mounted from buct132/nginx
  15. 305e2b6ef454: Mounted from buct132/nginx
  16. 24e065a5f328: Layer already exists
  17. latest: digest: sha256:eaa0d73ad93f9ce2ebe8df0059d028742bcf1c92aeaebf65e9c2a9b3558f7acd size: 1155
复制代码
使用 Docker 搭建 lnmp 环境

既然 Docker 可以直接启动 nginx 服务器,那么也肯定可以快速搭建 lnmp 环境。

为了方便管理,先新建一个项目目录:

  1. $ mkdir -p ./docker/mysql ./docker/php ./docker/nginx ./docker/php ./docker/project
  2. $ cd docker
复制代码

其中,

mysql 目录用于存放 mysql 的数据。 php 目录用于存放 php.ini 配置文件 nginx 目录用于存放 nginx 中的网站配置文件。 project 目录用于存放项目文件。 启动 MySql

一条命令即可快速启动一个mysql服务器:

  1. docker run -p 3306:3306 -v $PWD/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d --name mysql mysql
复制代码

运行后,docker 会自动从仓库中下载最新的 mysql 镜像,并设置为 root 密码为 123456 ,同时暴露出 3306 端口,容器命名为 mysql,并后台运行。

启动 PHP-FPM

这里的 php 使用 fpm 管理进程:
先新建一个 php.ini :

  1. $ touch php/php.ini
复制代码

配置文件中的配置项可以自行设置。

  1. docker run -p 9000:9000 -v $PWD/project:/usr/share/nginx/html -v $PWD/php/php.ini:/usr/local/etc/php/conf.d/php.ini --link mysql:mysql -d --name php7-fpm php:7.1-fpm
复制代码

从官方的 php7.1-fpm 为基础容器。因为要连接数据库,所以还得进入容器中安装 php 的 pdo_mysql 模块。

  1. leung@ubuntu:~$ docker exec -i -t php7-fpm /bin/bash
  2. root@d254489bd9e4:/var/www/html# cd /usr/local/bin/
  3. root@d254489bd9e4:/usr/local/bin# ./docker-php-ext-install pdo_mysql
  4. ...安装过程省略...
  5. root@d254489bd9e4:/usr/local/bin# php -m
  6. ...
  7. PDO
  8. pdo_mysql
  9. pdo_sqlite
  10. ....
复制代码

可以看到,已经安装上了 pdo_mysql 的模块。重启 php 容器即可。

  1. $ docker restart php7-fpm
复制代码
启动 nginx

之前已经成功启动nginx了,只需要在这基础上,增加 php 文件的解析就可以了。
同理,先新建一个 nginx 配置文件: $ touch nginx/default.conf

其中,配置文件中需要将 php 文件转发到 php-fpm 去处理即可,以前在宿主机中的配置一般都是转发到 127.0.0.1:9000,但是现在容器的 ip 是不固定的,所以直接填 php7-fpm:9000,启动容器时用 link 连接两个容器,让 docker 自动去识别容器的 ip 就可以了。当中的 php7-fpm 为 php-fpm 容器的名称。 php 文件路径要和 nginx 的文件路径保持一致。

  1. ...
  2. # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
  3. #
  4. location ~ \.php$ {
  5. # root html;
  6. fastcgi_pass php7-fpm:9000;
  7. fastcgi_index index.php;
  8. fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
  9. include fastcgi_params;
  10. }
  11. ...
复制代码

启动 nginx :

  1. docker run -p 80:80 -v $PWD/project:/usr/share/nginx/html -v $PWD/nginx/default.conf:/etc/nginx/conf.d/default.conf --link php7-fpm:php7-fpm -d --name nginx-fpm nginx
复制代码

此时,一个简易的 lnmp 环境已经搭好了,查看一下容器启动情况:

  1. leung@ubuntu:~/docker$ docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 490240532f1f nginx "nginx -g 'daemon ..." About an hour ago Up About an hour 0.0.0.0:80->80/tcp nginx-fpm
  4. d254489bd9e4 php:7.1-fpm "docker-php-entryp..." About an hour ago Up 27 minutes 0.0.0.0:9000->9000/tcp php7-fpm
  5. 7f184683cc8d mysql "docker-entrypoint..." 2 hours ago Up 2 hours 0.0.0.0:3306->3306/tcp mysql
复制代码
测试访问 php 文件

新建两个测试文件: touch project/index.php project/i.php

index.php

  1. <?php
  2. //date
  3. echo date("Y-m-d H:i:s")."<br />\n";
  4. try {
  5. $conn = new PDO('mysql:host=mysql;port=3306;dbname=mysql;charset=utf8', 'root', '123456');
  6. // 这里mysql 并不在同一个容器当中,所以连接数据库时,只需要填写 mysql 容器的名称即可。
  7. } catch (PDOException $e) {
  8. echo 'Connection failed: ' . $e->getMessage();
  9. }
  10. $conn->exec('set names utf8');
  11. $sql = "SELECT * FROM `user` WHERE 1";
  12. $result = $conn->query($sql);
  13. while($rows = $result->fetch(PDO::FETCH_ASSOC)) {
  14. echo $rows['Host'] . ' ' . $rows['User']."<br />\n";
  15. }
  16. ?>
复制代码

i.php

  1. <?php phpinfo(); ?>
复制代码

打开浏览器访问 http://10.211.55.9/i.php:

Dockerfile

虽然我们确实能快速搭建了一个 lnmp 的环境,但是每次切换宿主机时,都要执行多个步骤:

启动 mysql 服务器 启动 php 服务器 进入 php 容器修改配置

启动 nginx 服务器

  1. 怎么说都还是麻烦。如果能一键启动的话,那就更好了。
复制代码

Dockerfile 就可以解决这样的问题。

要使用 Dockerfile ,先要了解一下这到底是个什么东西。

什么是 Dockerfile?

A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession.

Dockerfile是一个文本文档,其中包含用户可以在命令行上调用以组合镜像的所有命令。使用docker构建用户可以创建一个自动构建,连续执行几个命令行指令。

Dockerfile 常用命令 FROM

语法: FROM [AS ] or FROM [:][AS ] or FROM [@][AS ]

注意:FROM 命令必须是 Dockerfile 的首个命令,但可以在一个 Dockerfile 中出现多次。

说明: 该命令定义了使用哪个基础镜像启动构建流程。基础镜像可以为任意镜像。

MAINTAINER

语法: MAINTAINER

说明: 设置生成镜像的作者名字。

RUN

语法:

RUN (shell形式,/bin/sh -c 或者是 Windows 的 cmd /S /C ) RUN ["", "", ""] (exec 形式)

说明:

RUN命令将在当前image中执行任意合法命令并提交执行结果。

RUN 指令缓存不会在下个命令执行时自动失效。

RUN命令用于创建镜像(在之前commit的层之上形成新的层)。

ADD

语法:

ADD [ ...] ADD ["", ... ""] (路径中包含空格的必须使用该形式)

注意:ADD只有在build镜像的时候运行一次,后面运行container的时候不会再重新加载了。

说明: 从 src 拷贝新的文件或文件夹或远程文件 URL 到镜像的文件系统的路径 dest 中。

所有拷贝到 container 中的文件和文件夹权限为 0755 , uid 和 gid 为0。 如果文件是可识别的压缩格式,则 docker 会自动解压缩。 如果 src 为本地文件或文件夹,则必须相对于 docker build 中的 目录中。 dest 是一个绝对路径,或者相对于 WORKDIR ,如果 不存在则会自动创建。 COPY COPY [ ...] COPY ["", ... ""] (路径中包含空格的必须使用该形式)

COPY 的语法和使用说明和 ADD 基本一致,但是在遇见压缩包时, COPY 很直接的拷贝到容器当中,而不会解压。 Docker 团队建议大多数情况下使用 COPY。

CMD

语法:

CMD ["","",""] exec 形式,比较好的形式。 CMD ["",""] 作为 ENTRYPOINT 的默认参数。 CMD shell 形式。

注意:Dockerfile 中只能有一个 CMD 指令,如果有多个则只有最后一个生效。

说明:

CMD 命令最主要的目的是提供一个默认的执行容器。

和RUN命令相似,CMD可以用于执行特定的命令。和RUN不同的是,这些命令不是在镜像构建的过程中执行的,而是在用镜像构建容器后被调用。

如果 CMD 用于为 ENTRYPOINT 提供默认参数时, CMD 和 ENTRYPOINT 指令应该规定为 JSON 数组格式。

当 docker run command 的命令匹配到 CMD command 时,会替换CMD执行的命令,即 docker run命令如果指定了参数会把CMD里的参数覆盖: (这里说明一下,如:docker run -it ubuntu /bin/bash 命令的参数是指/bin/bash 而非 -it ,-it只是docker 的参数,而不是容器的参数,以下所说参数均如此。)

ENTERYPOINT

语法:

ENTRYPOINT ["", "", ""] (exec 形式,推荐) ENTRYPOINT (shell 形式)

注意:Dockerfile 中只能有一个 ENTRYPOINT 指令,如果有多个则只有最后一个生效。

说明:

配置容器启动后执行的命令,并且参数不可被 docker run 提供的参数覆盖。

如果结合 CMD 使用时,要使用 exec 的形式,即:

  1. ENTRYPOINT ["echo"]
  2. CMD ["HELLO_WORLD"]
复制代码

这是 CMD 命令的内容则不是一个完整的指令,而是为 ENTRYPOINT 命令提供默认参数,该参数可以被 docker run 后的参数所覆盖。

EXPOSE

语法: EXPOSE [ ...]

说明: 通知 Docker 在运行时监听指定的端口。主机上要用还得在启动container时,做host-container的端口映射。

ENV

语法:

ENV ENV = [= ...]

说明:

该指令将环境变量的 key 设置为 value ,这些值都可以在 Dockerfile 后续的命令中用上,并可以被修改。

VOLUME

语法:

VOLUME ["", ...] VOLUME [ ...]

说明: 创建一个有具体名称的挂载点,并将其标记为从本机或者其他容器外部的挂载卷。

USER

语法: USER

说明: 指定某个用户运行容器。

WORKDIR

语法: WORKDIR

说明: 设定指令 CMD , RUN , ENTRYPOINT , COPY 和 ADD 的工作目录。可以在一个 Dockerfile 中出现多次,如果提供了一个相对路径,那么它将相对于前一个 WORKDIR 指令的路径。

ARG

语法: ARG [=default value>]

说明:

定义一个变量,用户可以在建立的时候通过 docker build 命令使用 —build-arg = 指定。 多条 ARG 指令可以定义指定的变量,但是在构建成功后取消。 相同名字的环境变量会被 ENV 指令的覆盖。 Docker 有一组预定义的 ARG 变量,可以在 Dockerfile 中使用而不需要 ARG 指令。 ONBUILD

语法: ONBUILD

说明:

当镜像作为另一个镜像构建的基础时,添加一个被延时执行的触发指令。就类似于在子镜像的 Dockerfile 的 FROM 指令下插入了一条命令。 ONBUILD 指定的命令在构建镜像时不执行,只在它的子镜像中执行。 任何构建指令都可以被注册为触发器,但 ONBUILD 指令不一定触发 FROM , MAINTAINER 或者 ONBUILD 指令。 Dockerfile 构建镜像

现在将先前搭建 lnmp 的具体步骤一步步写进 Dockerfile 中。

MySQL
  1. FROM mysql
  2. MAINTAINER LeungJZ
  3. ENV MYSQL_ROOT_PASSWORD 123456
  4. EXPOSE 3306
复制代码

没啥太多的配置,就是简单的配置ROOT密码和暴露3306端口。

构建镜像:

  1. leung@ubuntu:~/docker$ docker build ./mysql/ -t test-mysql
  2. Sending build context to Docker daemon 2.56kB
  3. Step 1/4 : FROM mysql
  4. ---> 141d24fea983
  5. Step 2/4 : MAINTAINER LeungJZ
  6. ---> Using cache
  7. ---> aa6665261e02
  8. Step 3/4 : ENV MYSQL_ROOT_PASSWORD 123456
  9. ---> Using cache
  10. ---> 4d482f48a09d
  11. Step 4/4 : EXPOSE 3306
  12. ---> Using cache
  13. ---> 385bb10cd49a
  14. Successfully built 385bb10cd49a
  15. Successfully tagged test-mysql:latest
复制代码

瞬间构建成功。再启动一个容器 docker run --name mysql -p 3306:3306 -d test-mysql ,和以前基本一致。

Php7.1-fpm
  1. FROM php:7.1-fpm
  2. MAINTAINER LeungJZ
  3. COPY php.ini /usr/local/etc/php/conf.d/php.ini
  4. RUN /usr/local/bin/docker-php-ext-install pdo_mysql
  5. EXPOSE 9000
  6. CMD ["php-fpm"]
复制代码

指定了 php-fpm 的版本为 7.1,并覆盖了我们自定义的 php.ini ,并且安装 pdo_mysql 拓展。

  1. leung@ubuntu:~/docker$ docker build ./php/ -t test-php7
  2. Sending build context to Docker daemon 70.14kB
  3. Step 1/6 : FROM php:7.1-fpm
  4. ---> 9b44e8b4c8b6
  5. Step 2/6 : MAINTAINER LeungJZ
  6. ---> Using cache
  7. ---> 1038ce686af9
  8. Step 3/6 : COPY php.ini /usr/local/etc/php/conf.d/php.ini
  9. ---> Using cache
  10. ---> cdbdece75628
  11. Step 4/6 : RUN /usr/local/bin/docker-php-ext-install pdo_mysql
  12. ---> Using cache
  13. ---> 8a8cbd9c8ac9
  14. Step 5/6 : EXPOSE 9000
  15. ---> Using cache
  16. ---> 1fd3881b6769
  17. Step 6/6 : CMD php-fpm
  18. ---> Using cache
  19. ---> 00d178a9351b
  20. Successfully built 00d178a9351b
  21. Successfully tagged test-php7:latest
复制代码

因为之前构建过一次,所以全都是从缓存中获取,直接就构建完成。

启动: docker run --name php7-fpm --link mysql:mysql -p 9000:9000 -v $PWD/project:/usr/share/nginx/html -d test-php7 。

nginx
  1. FROM nginx:1.13
  2. MAINTAINER LeungJZ
  3. COPY default.conf /etc/nginx/conf.d/default.conf
  4. EXPOSE 80
  5. ENTRYPOINT ["nginx", "-g", "daemon off;"]
复制代码

配置就是基础镜像为 1.13 版本的 nginx ,覆盖自定义的 default.conf 配置文件,暴露80端口,并且不以守护进程模式启动。

  1. leung@ubuntu:~/docker$ docker build ./nginx/ -t test-nginx
  2. Sending build context to Docker daemon 4.608kB
  3. Step 1/5 : FROM nginx:1.13
  4. ---> da5939581ac8
  5. Step 2/5 : MAINTAINER LeungJZ
  6. ---> Using cache
  7. ---> 3076338acc32
  8. Step 3/5 : COPY default.conf /etc/nginx/conf.d/default.conf
  9. ---> Using cache
  10. ---> bb7ab780e5d4
  11. Step 4/5 : EXPOSE 80
  12. ---> Using cache
  13. ---> 38dda9a94ae6
  14. Step 5/5 : ENTRYPOINT nginx -g daemon off;
  15. ---> Using cache
  16. ---> 7864bf277ac0
  17. Successfully built 7864bf277ac0
  18. Successfully tagged test-nginx:latest
复制代码

启动: docker run --name nginx --link php7-fpm:php7-fpm -v $PWD/project:/usr/share/nginx/html -p 80:80 -d test-nginx 。

访问 http://10.211.55.9/i.php 依旧可以看到熟悉的 phpinfo 的界面。

小结

Dockerfile 可以帮我们减轻了很多配置方面的麻烦,但是启动时,依旧需要绑定很多变量,如挂载卷,映射端口等。虽然只需 run 一次,但是这也是麻烦的。

当然,肯定有解决的办法,就是接下来的 docker-compose 。

docker-compose

Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.

Docker-compose 是一个定义和运行多容器 Docker 程序的工具。在 compose 中,可以用 YAML 文件来配置程序的服务,然后使用简单的命令即可从配置中创建并启动所有服务。

一个使用Docker容器的应用,通常由多个容器组成。使用Docker Compose,不再需要使用 shell 脚本来启动容器。在配置文件中,所有的容器通过 services 来定义,然后使用 docker-compose 脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器。

安装 compose

Linux:

  1. # 下载最新的 docker-compose
  2. sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
  3. # 给予下载的 docker-compose 执行权限
  4. sudo chmod +x /usr/local/bin/docker-compose
  5. # 测试是否可用
  6. docker-compose --version
  7. docker-compose version 1.15.0, build e12f3b9
复制代码

其他操作系统可以 查看这里 。

配置 docker-compose.yml

整个配置文件应该包含 version 、services 、 networks 三大部分,其中最关键是 services 和 networks 两部分。

version

下表显示了 compose 文件版本支持特定的 docker 版本。

Compose file format Docker Engine release
3.3 17.06.0+
3.2 17.04.0+
3.1 1.13.1+
3.0 1.13.0+
2.3 17.06.0+
2.2 1.13.0+
2.1 1.12.0+
2.0 1.10.0+
1.0 1.9.1.+
services

在 services 标签下的标签是指该服务的名称,为用户自定义。

image

  1. 指定服务的镜像名称或者镜像ID ,若本地不存在,则 compose 将会尝试拉取该镜像。
  2. 用法:
复制代码
  1. image: ubuntu
  2. image: nginx:1.13
  3. image: containerID
复制代码
  1. ?
复制代码

build

  1. 服务即可基于某个镜像 image ,亦可基于一个 Dockerfile 文件。在使用命令 `docker-compose up` 构建任务时,将会自动用 build 指向的 Dockerfile 路径构建镜像,并使用该镜像启动服务容器。
  2. **如果同时指定了 image 和 build,那么 compose 会将 build 出来的镜像命名为 image。**
  3. 用法:
复制代码
  1. build: ./nginx
  2. # 设定上下文目录
  3. build:
  4. context: ./
  5. Dockerfile: nginx/Dockerfile
复制代码

args

  1. 和 Dockerfile 中的 ARG 用法一样,在构建中指定环境变量,构建完成后取消。 args 中的变量可以为空值。
  2. **注意:如需要在 yaml 中使用布尔值(true,false, yes,no等)必须要用引号括起来。**
  3. 用法:
复制代码
  1. args:
  2. - version=1.0
  3. - boolean='true'
  4. - emptyvar
复制代码

command

  1. 可以覆盖启动容器后默认执行的命令。
  2. 用法:
复制代码
  1. command: nginx
  2. command: [nginx, -g, deamon off]
复制代码

container_name

  1. 设置容器的名称,默认为:<project><service><index>
  2. 用法:
复制代码
  1. container_name: lnmp_nginx
复制代码

depends_on

  1. 设置依赖。有时候某个容器需要另外一个容器作为依赖,则该命令可以解决依赖前后问题。如启动 nginx 前要先启动 php-fpm,这时候只需要这么写:
复制代码
  1. depends_on:
  2. - php-fpm
复制代码

entrypoint

  1. 用法和 Dockerfile 中的ENTRYPOINT 一致,会覆盖 Dockerfile 中的 ENTRYPOINT。
复制代码

environment

  1. 设置镜像中的环境变量,可以被保存在镜像当中,即每次启动容器,这些变量依旧存在容器当中。写法和 args 一致:
复制代码
  1. environment:
  2. - MYSQL_ROOT_PASSWORD: 123456
复制代码

expose

  1. 暴露容器中的端口,和 Dockerfile 中的EXPOSE 用法一致。
复制代码

links

  1. 类似于 `docker run` 中的 `—link` 参数,用于连接容器。如 nginx 容器需要连接 php-fpm 的容器,只需要这么写:
复制代码
  1. links:
  2. - php7-fpm:php
复制代码
  1. 其中,php 为 nginx 容器中连接 php 的别名,php7-fpm 为 php-fpm 服务的名字。
复制代码

ports

  1. 用于映射端口,用法和 `docker run` 的参数 `-p` 一致:
复制代码
  1. ports:
  2. - "8888:80"
复制代码
  1. 将容器的 80 端口映射到宿主机的 8888 端口中。
复制代码

volumes

  1. 挂载一个目录或者一个数据卷容器到 container 中。数据卷的路径可以是绝对的,相对的。
  2. 用法: `[HOST:CONTAINER]` or `[HOST:CONTAINER:rw]` rw的意思是,容器对该卷可读可写;ro为只读。
复制代码
  1. volumes:
  2. # 只在容器中创建一个数据卷
  3. - /website/html
  4. # 绝对路径
  5. - /home/website:/website/html
  6. # 相对路径
  7. - ./data:/website/html
  8. # 已存在的数据卷容器,并设置权限为只读
  9. - data_container:/website/html:ro
复制代码
  1. ?
复制代码

volumes_from

  1. 从其他容器或者服务挂载数据卷,可选参数为 `:ro` 只读 或者 `:rw` 可读可写。默认为可读可写。
复制代码

networks

  1. 指定容器加入的网络:
复制代码
  1. services:
  2. nginx:
  3. networks:
  4. web_app
复制代码
  1. web_app 为网络名称。
复制代码

还有其他的配置项,具体的可以去 官网查看 。

编写一个多容器配置

先创建如下目录:

  1. ./
  2. ├── conf // 配置文件目录
  3. │ ├── mysql
  4. │ ├── nginx
  5. │ └── php
  6. ├── data // mysql 数据目录
  7. ├── logs // 日志文件目录
  8. │ ├── mysql
  9. │ ├── nginx
  10. │ └── php
  11. └── www // 项目目录
复制代码

新建一个 docker-compose.yml 文件:

  1. version: '2'
  2. services:
  3. nginx:
  4. image: nginx:1.13
  5. ports:
  6. - "80:80"
  7. volumes:
  8. - ./www:/usr/share/nginx/html:rw
  9. - ./logs/nginx/:/var/log/nginx:rw
  10. - ./conf/nginx/conf.d:/etc/nginx/conf.d:ro
  11. links:
  12. - php:fpm
  13. depends_on:
  14. - php
  15. php:
  16. build: ./conf/php
  17. ports:
  18. - "9000:9000"
  19. volumes:
  20. - ./www:/usr/share/nginx/html:rw
  21. - ./logs/php/:/var/log/php:rw
  22. links:
  23. - mysql:mysql
  24. depends_on:
  25. - mysql
  26. mysql:
  27. image: mysql:5
  28. ports:
  29. - "3306:3306"
  30. volumes:
  31. - ./mysql:/var/lib/mysql:rw
  32. environment:
  33. MYSQL_ROOT_PASSWORD: "123456"
  34. MYSQL_USER: "test"
  35. MYSQL_PASSWORD: "testpass"
复制代码

version 为2 可以兼容旧版本的docker。

services 这里一共启动了3个服务:

nginx。监听 80 端口,挂载了 www 目录为工作目录,挂载 logs/nginx 为日志目录,挂载 conf/nginx/conf.d 至容器的 nginx 的配置文件夹。连接 php 容器,表示为 fpm。依赖于 php 容器。 php。 监听 9000 端口,挂载 www 目录为工作目录,挂载 logs/php 为日志目录,依赖于 mysql 容器并连接 mysql 容器。 mysql。监听 3306 端口,挂载 mysql 目录为 mysql 数据存储目录,并设置了3个环境变量,分别为 root密码,mysql 用户 test 并设置 test 的密码为 testpass。

配置文件自行添加,最终的目录结构为:

  1. .
  2. ├── conf
  3. │ ├── mysql
  4. │ ├── nginx
  5. │ │ └── conf.d
  6. │ │ ├── default.conf
  7. │ │ └── home.conf
  8. │ └── php
  9. │ ├── Dockerfile
  10. │ └── php.ini
  11. ├── docker-compose.yml
  12. ├── logs
  13. │ ├── mysql
  14. │ ├── nginx
  15. │ └── php
  16. ├── mysql
  17. └── www
  18. ├── home
  19. │ └── index.html
  20. ├── index.html
  21. ├── index.php
  22. └── i.php
复制代码

因为 php-fpm 我们需要做额外的事情,所以使用 Dockerfile 来构建镜像。php 的 Dockerfile 的内容配置和之前的 Dockerfile 一致:

  1. FROM php:7.1-fpm
  2. MAINTAINER LeungJZ
  3. COPY php.ini /usr/local/etc/php/conf.d/php.ini
  4. RUN docker-php-ext-install pdo_mysql
  5. EXPOSE 9000
  6. CMD ["php-fpm"]
复制代码

可以在 RUN 命令中,安装需要的 php 拓展。

在项目根目录中运行命令 docker-compose up 开始构建。

  1. leung@ubuntu:~/compose$ docker-compose up
  2. Pulling mysql (mysql:5)...
  3. 5: Pulling from library/mysql
  4. aa18ad1a0d33: Already exists
  5. fdb8d83dece3: Pull complete
  6. 75b6ce7b50d3: Pull complete
  7. ed1d0a3a64e4: Pull complete
  8. 8eb36a82c85b: Pull complete
  9. 41be6f1a1c40: Pull complete
  10. 0e1b414eac71: Pull complete
  11. 914c28654a91: Pull complete
  12. 587693eb988c: Pull complete
  13. b183c3585729: Pull complete
  14. 315e21657aa4: Pull complete
  15. Digest: sha256:0dc3dacb751ef46a6647234abdec2d47400f0dfbe77ab490b02bffdae57846ed
  16. Status: Downloaded newer image for mysql:5
  17. Building php
  18. Step 1/6 : FROM php:7.1-fpm
  19. ---> 9b44e8b4c8b6
  20. Step 2/6 : MAINTAINER LeungJZ
  21. ---> Running in e5c103cc2d37
  22. ---> c396815cf8b6
  23. Removing intermediate container e5c103cc2d37
  24. Step 3/6 : COPY php.ini /usr/local/etc/php/conf.d/php.ini
  25. ---> bc4a19e69f93
  26. Removing intermediate container 566b27944ffb
  27. Step 4/6 : RUN /usr/local/bin/docker-php-ext-install pdo_mysql
  28. ---> Running in 8ebd9dadf506
  29. ---> a3483051c1bb
  30. Removing intermediate container 8ebd9dadf506
  31. Step 5/6 : EXPOSE 9000
  32. ---> Running in 9a4f81103c0c
  33. ---> d0376a2a8bfe
  34. Removing intermediate container 9a4f81103c0c
  35. Step 6/6 : CMD php-fpm
  36. ---> Running in 8d7f61c657f9
  37. ---> 77072c6b2561
  38. Removing intermediate container 8d7f61c657f9
  39. Successfully built 77072c6b2561
  40. Successfully tagged compose_php:latest
  41. WARNING: Image for service php was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
  42. Creating compose_mysql_1 ...
  43. Creating compose_mysql_1 ... done
  44. Creating compose_php_1 ...
  45. Creating compose_php_1 ... done
  46. Creating compose_nginx_1 ...
  47. Creating compose_nginx_1 ... done
  48. Attaching to compose_mysql_1, compose_php_1, compose_nginx_1
复制代码

不出1分钟,整个项目环境就已经搭建好了。根据提醒, php 服务已经被构建出来了,因为它一开始并不存在。如果想要重新构建整个服务,需要运行 docker-compose build or docker-compose up --build 。

这时 docker ps 查看:

  1. leung@ubuntu:~$ docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 18bc61bd12b1 nginx:1.13 "nginx -g 'daemon ..." About a minute ago Up About a minute 0.0.0.0:80->80/tcp compose_nginx_1
  4. 38ccb807e09b compose_php "docker-php-entryp..." About a minute ago Up About a minute 0.0.0.0:9000->9000/tcp compose_php_1
  5. 67188d651b80 mysql:5 "docker-entrypoint..." About a minute ago Up About a minute 0.0.0.0:3306->3306/tcp compose_mysql_1
复制代码

可以看到已经成功启动了三个容器。

通过浏览器访问:

可以发现已经运行成功,而且 php 文件也能正常执行。

docker-compose 命令

和 docker 差不多,也有 start , stop, build , logs , rm 等常用命令,其作用也是类似的。

总结

docker 真是一个神器!!!

这只是一个简单的入门,希望大家能继续挖掘 docker 更强大的功能。



太阳http代理AD
回复

使用道具 举报