这些翻白眼的鲸鱼背上是一整个世界!

这些翻白眼的鲸鱼背上是一整个世界!

编程那点事 随便写写 PHP Linux 2577 字 / 5 分钟

初见

我不记得自己第一次听说 Docker 是在什么时候了。最初是联想到 macOS 里的 Dock 栏,以为是个什么应用程序。 直到偶然见到了她的 Logo——背着集装箱的翻着白眼的鲸鱼。

还真别说,这 Logo 还挺可爱的。但是百度过后,我一头雾水。容器引擎?虚拟化?沙箱?这都什么鬼咯? 可以说 Docker 所代表的“容器”这一概念,和我之前一直理解的“虚拟机”的概念有很大的不同。因此我无法理解一个应用程序怎么能单独放在一个容器一样的盒子中呢?脱离了操作系统它还能跑?(之后我才发现,一个装了 PHP 镜像的容器,进去内部才发现居然有 Linux 一样的文件目录,并且系统就是我外部服务器的系统……)

到底是干嘛用的?

看了很多网上的文章,我还是不理解 Docker 到底能用来干什么。直到在自己做东西时遇到了问题——我之前搭建过 Jenkins 来实现 PHP 的项目自动部署,但是 Jenkins 服务貌似和其它服务有冲突,过了一会儿就会自己挂掉。之后只能自己手动重启。我便想找个可以将各个应用给隔离起来的办法,这时,这头鲸鱼出现了。

还真挺好用

Li4n0 学长说 Docker 是改变世界的产品。这句话,我现在是无比的赞同。 Docker 上手真的很快,首先先分清三个核心概念:

镜像

镜像就是我们想要运行的应用,镜像是只读的。在官方的 Docker Hub 上有数十万个镜像可以下载。

搜索镜像:

docker search IMAGENAME

下载镜像:

docker pull IMAGENAME:TAG

查看本地的镜像

docker images

删除本地镜像

docker rmi IMAGENAME:TAG

容器

容器就是镜像的一个运行实例。从技术上来说,容器是在静态的只读镜像上,加了一个可写的文件层。

创建并启动一个容器:

docker run -d --name CONTAINER_NAME -p OUT_PORT:INSIDE:PORT -e ENVIROMENT_SETTING --link CONTAINER_NAME:ALIAS -v LOCAL_DIR:CONTAINER_DIR IMAGE_NAME

这是十分常用的一条命令,以下列举了几个常用参数:

  • -d 使得容器可以后台运行(守护态运行),不会在退出后就关闭
  • –name 容器的名字,如果不设置的话,Docker 随机生成一个十分搞笑的蠢名字
  • -p 端口映射,格式是 外部端口:容器内部端口
  • -e 容器的相关环境变量设置,比如新建一个 mysql 容器,就是在这里设置 mysql 的 root 密码的
  • –link 容器互联,使得容器简互联访问,其中 ALIAS 为别名,在其他容器中使用别名来访问
  • -v 文件映射 将服务器上的文件 / 文件夹映射到容器内部。格式是: 本地目录:容器内目录

查看所有容器

docker ps -a

如果不带 -a 参数的话,则显示所有已启动的镜像。

删除容器

docker rm CONTAINER_NAME

启动 / 停止 / 重启容器

docker start CONTAINER_NAME
docker stop CONTAINER_NAME
docker restart CONTAINER_NAME

进入容器

docker exec -it CONTAINER_NAME bash

这是十分有用的命令,虽然也可以使用 docker attach CONTAINER_NAME,但是个人更推荐上面这种。 其中 -i 参数是“打开标准输入接受用户输入命令”,其实就是使得你可以进入容器后在当前 bash 上输入命令。 -t 是“分配为为终端”。 而最后的 bash 就是我们要运行的程序了,直接打开容器的 bash 进行操作。当然你也可以改成 vim /etc/YOUR_FILE 这种,直接开 vim 开编辑文件。(然而我用 nano)

退出容器

exit

仓库

Docker 仓库就是装各种 Docker 镜像的地方。比如 Docker 官方的 DockerHub,这一点可以类比 Git 仓库。

PS:以上的命令,我这几天踩了很多坑,不断重装尝试,每条至少输入了不下 20 遍…… 根本不会忘了,哈哈。

实践:使用 Docker 搭建一个 PHP 环境

总算开始干正事了啊~ 之前在群里问过 Li4n0 学长,说是应该只用一个 LNMP 镜像将所有东西全部装在一个容器里,还是将 Nginx、MySQL、PHP 分别单独装在不同容器里,然后 --link 起来呢? 学长说选择后者。嗯,那就开始吧。

拉取镜像

首先是先把三个的镜像拉到本地:

docker pull nginx
docker pull mysql
docker pull php:7.0-fpm

注意这里我是安装了 PHP 7.0,你可以按照自己的喜好来。

开始安(cai)装(keng)!

安装这里的坑真的超级多,且听我一一道来。 首先是安装的顺序问题。Nginx 需要 link 上 PHP,PHP 又要 link 上 MySQL,因此我们应该先装 MySQL。

安装并配置 MySQL

docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /home/app/mysql:/var/lib/mysql --name mysql_container mysql

可以看到我们将 MySQL 容器内的 3306 端口映射到了外部的 3306 端口,并且使用 -e 参数设置了 MySQL 数据库的 root 密码;同时将外部的文件夹映射到了容器内的数据文件夹;容器名为:mysql_container*(请记住这个名字哦!)* 这个时候 MySQL 就已经开始跑了。

进入 MySQL 容器中:

docker exec -it mysql_container bash

进入 mysql:

mysql -uroot -p

输入密码后进入,之后对用户进行授权:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'127.0.0.1' IDENTIFIED BY '123456';
FLUSH PRIVILEGES;

完事,退出 MySQL:

quit

安装并配置 PHP

docker run -p 9000:9000 --name php7fpm -v /home/app/html:/var/www/html -v  /home/app/phpfile:/usr/local/etc/php --link mysql_container  -d php:7.0-fpm

这里我们将 PHP 的 9000 端口映射到了外部 9000 端口,之后会在 Nginx 中配置,将所有的 .php 文件都从 9000 端口丢给 PHP 去处理;容器名字是 php7fpm;将服务器上的放置站点文件夹映射了进来,并且将本地放有 PHP 配置的文件夹也映射进了容器内;再与 mysql_container 容器进行互联;并且设置了守护态运行。

在 /home/app/phpfile 文件夹下创建 php.ini 文件和 conf.d 文件夹,前者是 PHP 的配置文件,后者是装 Nginx 配置的文件夹,都会映射进入容器内。 修改 php.ini 文件,加上数据库扩展:

extension=php_curl.dll
extension=php_gd2.dll
extension=php_mysql.dll
extension=php_mysqli.dll
extension=php_pdo_mysql.dll
extension=php_pdo_odbc.dll
extension=php_pdo.dll

安装并配置 Nginx

首先先在 conf.d 文件夹下创建一个 default.conf 文件来记录 nginx 的配置。(你也可以不叫 default,Nginx 是会读取该目录下所有 conf 后缀的文件的) 输入 Nginx 配置:

server
{
		listen 80;
		 server_name localhost;
		location / {
				root /usr/share/nginx/html;
				index index.php index.html index.htm;
		}
		  location ~ \.php$ {
				fastcgi_pass php7fpm:9000;  #此处写 Docker 里边 php 容器的名称: php7fpm
				fastcgi_index index.php;
				fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
				include fastcgi_params;
		  }
		error_page 500 502 503 504 /50x.html;
		location = /50x.html {
			root /usr/share/nginx/html;
		}
}

注意在 fastcgi_pass 这里填写的是上面 PHP 镜像的名称,并且端口号就是之前映射的 9000。这样 Nginx 就会把所有 PHP 文件转到 9000 端口给后端处理啦~ 并且这里就出现了一个超大的坑——以上 Nginx 配置文件是从 CSDN 复制的,原网站中,相关的空格与缩进貌似是一些奇怪的空白字符,表面上完全看不出来,但是 Nginx 容器在启动后会瞬间关闭。到 Vidar 找了 Li4n0 学长,然后他直接输了这么一行:

docker logs nginx

直接显示出了 nginx 容器的运行日志,发现了问题所在。

下面启动 PHP 吧:

docker run -p 80:80 -p 443:443  --name nginx -v /home/app/www:/usr/share/nginx/html -v /home/app/phpfile/conf.d:/etc/nginx/conf.d --link php7fpm -d nginx

这里将 HTTP 的 80 端口,以及 HTTPS 的 443 端口映射到了容器内;并且映射了 Nginx 的站点文件夹与配置文件夹;同时关联了 PHP 容器。

好的,至此我们就已经成功在 Docker 上搭建好了 PHP 环境。 之后还可以选择搭建 phpmyadmin 镜像以及 Jenkins 镜像,方法都大同小异,在这里就不再赘述了。

总结一下吧

虽然这几天搞下来踩了不少坑,但是还是真的被 Docker 的强大易用所折服。把很多有意思的镜像都下载下来玩了一下,玩脱了就删掉,十分舒服。现在已经是挺熟练了。 也超级感谢 Li4n0 大佬的帮助,解决了困扰我一天的问题。祝愿他早日找到女朋友。 这一波搞下来,我对 Linux 也熟悉了不少,然而之后肯定是要系统地去学的啦。顺带一提,CentOS 7 以上的版本貌似预装 Docker,但是在我尝试使用过 Ubuntu 后,就已经决定告别 CentOS 了……

嗯,就是这样,Docker 暂且算是告一段落了。接下来还是继续好好看我的 JavaScript 和 Python 吧。 爱死这些翻白眼的鲸鱼了!