@dungan
2020-11-17T01:12:46.000000Z
字数 8015
阅读 107
Docker
在 ubuntu 容器中借助 oneinstack 安装包生成 Lnmp 环境,然后将此 Ubuntu 容器打包成一个镜像:
# 启动 ubuntu 容器
$ docker run -itd --name ubuntu ubuntu:latest
1692725c0b57e5c9a0cc620bb95124d7ab1f8588dd4e8ee77c805dd2175cb679
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1692725c0b57 ubuntu:latest "/bin/bash" 5 seconds ago Up 4 seconds ubuntu
# 进入 ubuntu 容器
$ docker exec -it ubuntu bash
# 一键安装 Lnmp
root@1692725c0b57:/# wget -c http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz && ./oneinstack/install.sh --nginx_option 1 --php_option 7 --phpcache_option 1 --php_extensions imagick,fileinfo,redis,memcached,memcache,mongodb,swoole,xdebug --phpmyadmin --db_option 2 --dbinstallmethod 1 --dbrootpwd oneinstack --pureftpd --redis --memcached --iptables --reboot
# 安装 composer
root@1692725c0b57:/# curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
root@1692725c0b57:/# exit
exit
# 将ubuntu容器打包成一个镜像
$ docker commit -m "lnmp images" -a "dunagan" 1692 dungan/lnmp
sha256:46b19a77fef2cf601732009643f51a0aa8a251d9bfb47066d269fd5e291a39e4
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dungan/lnmp latest 46b19a77fef2 About a minute ago 4.08GB
...
# 基于刚刚打包的 dungan/lnmp 镜像启动一个容器
$ docker run -it dungan/lnmp:latest bash
root@56fd2d4408d0:/# php -v
PHP 7.2.32 (cli) (built: Jul 23 2020 17:45:14) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.32, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v2.9.5, Copyright (c) 2002-2020, by Derick Rethans
root@56fd2d4408d0:/# nginx -v
nginx version: nginx/1.18.0
这样构建的集成式Lnmp环境就运行起来了,但还有几个问题需要解决下。
使用 composer :
// 第一种:
docker run --rm -w /data/www/project composer:latest composer update
// 第二种
docker exec -it f9 /usr/local/bin/composer -V
// docker exec -it f9 /bin/sh -c "/usr/local/bin/composer -V"
如果运行composer时出现如下错误 :
$ docker exec -it f9 /bin/sh -c "/usr/local/bin/composer"
/usr/bin/env: 'php': No such file or directory
这是由于 php 没有在 /usr/bin 下找,修复此问题只需要做个软链接就可以了 :
// 为了避免 docker exec 时我们需要全路径引用相关的服务,对 nginx,composer也做下软连接
ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
ln -s /usr/local/php/bin/php /usr/bin/php
默认情况下,docker 为了安全起见支支持 从 unixsock 连接,而不支持通过 TCP 连接,但 PhpStorm 又必须通过 TCP API 的方式连接 Docker 中的 php CLI interpreter,因此为了支持 Docker Daemon
通过Remote API 连接做如下配置:
$ vim /etc/docker/daemon.json
{
"registry-mirrors":["https://hub-mirror.c.163.com/"],
"debug": true,
"hosts": ["tcp://localhost:2375","unix:///var/run/docker.sock"]
}
$ service docker restart
然后我们在 phpStorm 中就可以通过 TCP API 连接 Docker 了,关于这块的具体介绍见 这里。
最后我们试着将生成的镜像 dungan/lnmp:latest
Push 到 DockerHub。
- 在 docker-hub 新建镜像仓库:例如叫做 lnmp,这类似 github,每个项目都有自己的仓库。
- 修改镜像名称:格式为为
<username>/<reponame>:<tagname>
,例如 dungan/lnmp:v1.0- 登录 DockerHub: docker login
- push 镜像:docker push dungan/lnmp:latest
$ docker push dungan/lnmp:latest
The push refers to repository [docker.io/dungan/lnmp]
349ed4d1fa0d: Pushing [===> ] 276MB/4.004GB
544a70a875fc: Pushed
cf0f3facc4a3: Pushed
132bcd1e0eb5: Pushed
d22cfd6a8b16: Pushed
很不幸会失败的,因为我们构建出来的这个镜像 dungan/lnmp 大小竟然为 4.08G。
可以看到这种集成式的 Lnmp 环境问题多多,我们只能另辟蹊径,看看将各个组件独立成单一的容器能带给我们那些不一样的收获。
独立的容器组件首先遇到的是互相通信的问题,对此 docker 提供了两种解决方案:自定义网络
和 容器互联
。
容器默认加入的网络 bridge 便是 docker0,我们可以通过docker network inspect
命令来查看一下这个 bridge 网络:
$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "499548da01b39013949d6e22f2b1afa6db2153246850ebd9e860ca1860094316",
"Created": "2020-07-24T18:01:04.9259454+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"1692725c0b57e5c9a0cc620bb95124d7ab1f8588dd4e8ee77c805dd2175cb679": {
"Name": "ubuntu",
"EndpointID": "e88b34e46377429d5598b0e7dd01d27f321c3d10b6541b72db599193ac433ddb",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"56fd2d4408d091df243f468a6558891d683f58a6437e47a71510f184b7abd7d0": {
"Name": "lnmp",
"EndpointID": "dec4ea0917479775fa91bd373c0f437882b01145bbfca8e28592a2eaaa79e648",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
}
...
}
]
Docker 支持用户手动创建网络,以及手动将容器加入某个网络:
docker network create lnmp
docker network connect lnmp mysql
docker network connect lnmp nginx
通过 docker inspect CONTAINER 命令来查看容器信息,可以看到两个容器分别获得了 172.18.0.2 和 172.18.0.3 的IP,他们之间可以通过这一子网进行通信了。
可以看到通过加入相同子网(默认的bridge或者自定义子网)的容器可以实现互相通信。
--link 容器互联的原理:
--link 实现容器互联的原理是通过修改容器内的 hosts 文件,比如容器A --link 容器B,这时 Docker 就会修改容器 A 的 hosts 文件,将容器 B 及对应的 IP 添加进去。但使用 --link 会造成容器之间的绑定,前面的例子中,若删除容器B,容器A将无法运行,即使重新创建一个相同名称的容器B,容器A仍然无法运行,这显然是我们不想看到的。
不过需要注意:
Docker 官方文档已经明确提出 --link将在未来版本中移除,鼓励使用自定义网络来实现用户间的通信,并指出例如共享环境变量这样可以通过--link实现而无法通过自定义网络实现的功能则推荐使用volumes的方式解决。
将配置文件复制出来,方便后续重新启动容器时进行数据卷映射。
Nginx:
$ docker run --name nginx -d nginx
$ docker cp nginx:/etc/nginx /mnt/d/docker/nginx
$ docker cp nginx:/usr/share/nginx/html /mnt/d/docker/www
$ docker stop nginx
$ docker rm nginx
$ ll /mnt/d/docker/
drwxrwxrwx 1 tcl tcl 4096 Jul 22 11:23 nginx/
drwxrwxrwx 1 tcl tcl 4096 Jul 22 11:23 www/
MySQL:
$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -d -p 3306:3306 mysql:5.7
$ docker cp mysql:/etc/mysql /mnt/d/docker/mysql
$ docker stop mysql
$ docker rm mysql
$ ll /mnt/d/docker/
drwxrwxrwx 1 tcl tcl 4096 Jul 23 04:15 mysql/
drwxrwxrwx 1 tcl tcl 4096 Jul 22 11:23 nginx/
drwxrwxrwx 1 tcl tcl 4096 Jul 22 11:23 www/
PHP-FPM:
$ docker run --name phpfpm -d -P php:7.2-fpm
$ docker cp phpfpm:/usr/local/etc/php /mnt/d/docker/php
$ docker stop phpfpm
$ docker rm phpfpm
$ ll /mnt/d/docker/
drwxrwxrwx 1 tcl tcl 4096 Jul 23 04:15 mysql/
drwxrwxrwx 1 tcl tcl 4096 Jul 22 11:23 nginx/
drwxrwxrwx 1 tcl tcl 4096 Jul 22 19:14 phpfpm/
drwxrwxrwx 1 tcl tcl 4096 Jul 22 11:23 www/
重新运行各个容器以作数据卷映射。
Nginx:
docker run -d -it --name nginx \
-v /mnt/d/docker/nginx:/etc/nginx \
-v /mnt/d/docker/www:/usr/share/nginx/html \
-p 80:80 \
-p 443:443 \
nginx \
/bin/bash
MySql:
docker run -d -it --name mysql \
-e MYSQL_ROOT_PASSWORD=root \
-v /mnt/d/docker/mysql:/etc/mysql \
-p 3306:3306 \
mysql:5.7 \
/bin/bash
PHP:
由于 docker 官方的 php-fpm 为了减少体积并未包含大部分扩展,因此为了安装没有的扩展,我们构造 Dockerfile 如下:
FROM php:7.2-fpm
RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak \
&& echo 'deb http://mirrors.aliyun.com/debian/ buster main non-free contrib' > /etc/apt/sources.list \
&& echo 'deb http://mirrors.aliyun.com/debian-security buster/updates main' >> /etc/apt/sources.list \
&& echo 'deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib' >> /etc/apt/sources.list \
&& echo 'deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib' >> /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
libmagickwand-dev \
libmcrypt-dev \
&& rm -rf /var/lib/apt/lists/* \
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install mysqli \
&& pecl install imagick-3.4.4 && pecl install mcrypt-1.0.2 && pecl install redis-5.1.1 \
&& pecl install xdebug-2.7.2 && pecl install swoole-4.4.3 \
&& docker-php-ext-enable imagick mcrypt redis xdebug swoole \
&& curl -sS https://getcomposer.org/installer |php -- --install-dir=/usr/local/bin --filename=composer
&& docker-php-source delete \
&& rm -r /tmp/* /var/cache/* /var/www/html/*
注意:上述 Dockerfile 中我们一并打包了 composer,更多关于php扩展的安装见 这里 和 docker官方。
接下来,基于 Dockefile 构造我们自己的 phpfmp 镜像:
$ docker build -t dungan/phpfpm7.2 .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dungan/phpfpm7.2 latest 1c0ef877da7e 2 hours ago 631MB
最后基于此镜像启动一个容器:
docker run --name phpfpm -d -P \
-v /mnt/d/docker/www:/usr/share/nginx/html \
-v /mnt/d/docker/php:/usr/local/etc/php \
dungan/phpfpm7.2:latest
注意:站点下的 php 脚本如果想在 CLI 模式下执行,就必须将 www 映射到 phpfpm 容器中去。
创建自定义网络,将各容器加入该自定义网络。
$ docker network create lnmp
2c934afb36b871ea49f911c87e7beb3cd6279e18853f2c31d625e718db64f68c
$ docker network connect lnmp nginx
$ docker network connect lnmp mysql
$ docker network connect lnmp phpfpm
修改nginx配置文件:
server{
...
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass phpfpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
...
}
然后重启 Nginx :
$ docker restart nginx