第3次实践作业
Docker Compose 安装与卸载
在 Linux 上安装docker compose十分简单,从 官方 GitHub Release 处直接下载编译好的二进制文件即可。
$ sudo curl -L https://github.com/docker/compose/releases/download/1.26.0-rc4/docker-compose-Linux-x86_64 >> /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
使用docker-compose --version
,出现如下提示表示安装成功。
docker-compose version 1.26.0-rc4, build d279b7a8
构建LNMP服务
在docker-compose.yml
文件中使用 build
指令时, Dockerfile
中设置的选项(例如:CMD
, EXPOSE
, VOLUME
, ENV
等) 将会自动被获取,无需在 docker-compose.yml
中再次设置。为了减少docker-compose.yml
的篇幅,本次实验大多使用Dockerfile
进行设置。
Dockerfile编写
Nginx
nginx在LNMP服务中充当着web代理服务器的角色,需要通过nginx来定位需要使用的web服务。首先修改nginx的相关配置。需要注意的配置选项是root
、fastcgi_pass
和fastcgi_param
,如果这些选项配置不正确,将会出现一系列的not found
问题。
...
server {
listen 80;
server_name localhost;
...
location / {
root /usr/share/nginx/myhtml;
index index.html index.htm;
}
...
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /var/www/myphp;
fastcgi_pass myphp:9000; # 容器名:端口号
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
...
Dockerfile配置比较简单,代码如下所示:
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
RUN mkdir /usr/share/nginx/myhtml
EXPOSE 80
MySQL
MySQL在LNMP服务中充当数据库的角色,根本职责就是存储结构化数据。在MySQL容器启动过程中,建立了一个数据库、一个基本表并往基本表加入一个元组的数据,以用于查看MySQL是否初始化正确。
Dockerfile完整代码如下:
FROM mysql
ENV MYSQL_ROOT_PASSWORD=123456 \
MYSQL_ALLOW_EMPTY_PASSWORD=no \
MYSQL_DATABASE=mydb
COPY mytable.sql /docker-entrypoint-initdb.d
EXPOSE 3306
创建基本表以及插入数据的sql语句如下:
use mydb;
create table student(
id int(4) not null primary key,
name varchar(16) not null
)DEFAULT CHARSET=latin1;
INSERT INTO student VALUES (1, 'My LNMP-MySQL.');
PHP
PHP在LNMP服务中充当的是对数据库进行操作的角色,因为需要连接MySQL,所以需要安装PHP Core Extensions
以及pdo
扩展。在阅读PHP Docker Official Images中的
并加以适当修改,可以得到如下完整的Dockerfile代码:
FROM php:7.4-fpm
COPY sources.list /etc/apt # 更改镜像源
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install pdo pdo_mysql # 安装pdo
ENV MYSQL_ROOT_PASSWORD=123456
docker-php-ext-install pdo pdo_mysql
添加了连接MySQL相关的组件,MYSQL_ROOT_PASSWORD=123456
环境变量方便PHP连接到MySQL。
使用Compose实现多容器运行机制
docker-compose.yml
docker-compose.yml
文件时docker-compose的关键文件,它通过yml文件获知需要部署的应用的整体框架以及相关细节。
version: "3"
services:
web:
container_name: myweb
build: ./myNginx
ports:
- "80:80"
volumes:
- /var/lib/myLNMP/nginx:/usr/share/nginx/myhtml
db:
container_name: mydb
build: ./myMySQL
ports:
- "3306:3306"
volumes:
- /var/lib/myLNMP/mysql:/var/lib/mysql
php:
container_name: myphp
build: ./myPHP
volumes:
- /var/lib/myLNMP/php:/var/www/myphp
phpmyadmin:
container_name: myphpmyadmin
image: phpmyadmin/phpmyadmin:latest
ports:
- "8080:80"
environment:
- PMA_ARBITRARY=1
在yml文件中,container_name
创建容器后的容器名;build
表示使用Dockerfile定制镜像,它后面跟上Dockerfile文件所在的目录,默认的上下文路径与Dockerfile文件所在目录相同;ports
表示端口映射;volumes
表示将容器内的文件目录持久化到本地目录,可以使用该方法避免每一次开启容器后,数据重新初始化导致数据丢失;image
表示镜像来源;environment
表示设置环境变量。
在该实验中,phpmyadmin容器可以直接使用原生镜像,而不需要使用Dockerfile进行定制。
整个应用项目所需文件并不多,使用tree -L
命令可以很清楚地看到文件目录。
做好上述的准备工作后,就可以在docker-compose.yml
文件所在的目录中,使用docker-compose up
命令进行项目部署。
看到一连串的done
之后,项目就部署成功了。
将nginx的主页index.html
放到root
所在的持久化目录(上文中的/var/lib/myLNMP/nginx)下,并在浏览器上,登录http://hostname/就能看到nginx的主页。index.html的内容是<h1>My LNMP-Nginx.</h1>
使用navicat登录MySQL,并查看相关初始化。
在navicat中可以看到,相关数据库、基本表均初始化正确。
将PHP的主页index.php
放到root
所在的持久化目录(上文的/var/lib/myLNMP/php)下,就能够访问了。index.php的内容是<?php phpinfo();?>
下滑,可以看到pdo相关组件安装成功。
以上,LNMP服务成功部署,接下来通过PHP对MySQL进行测试。
服务测试
连接测试
首先,使用PHP对MySQL进行连接测试。在PHP的root持久化目录中新建一个connect2DB.php
,并向其中输入如下代码:
<?php
$servername = "mydb"; // 上述的数据库容器名
$username = "root";
$password = $_ENV["MYSQL_ROOT_PASSWORD"];
try {
$conn = new PDO("mysql:host=$servername;", $username, $password);
echo "连接成功";
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
在浏览器中,通过URL的方式,访问该web服务。出现连接成功
,即表示PHP与MySQL无障碍通信。
同样,在PHP的持久化目录下,新建一个PHP2DB.php
文件,并输入如下代码:
<?php
$servername = "mydb"; // 上述的数据库容器名
$username = "root";
$password = $_ENV["MYSQL_ROOT_PASSWORD"];
try {
$conn = new PDO("mysql:host=$servername;", $username, $password);
echo "连接成功";
}
catch(PDOException $e)
{
echo $e->getMessage();
}
//创建数据库和基本表
$conn->exec("create database if not exists phpdb;");
echo "数据库创建成功!<br>";
$conn->exec("use phpdb;");
$conn->exec("create table if not exists student(
id int(4) not null primary key,
name varchar(16) not null
)DEFAULT CHARSET=latin1;");
echo "表格创建成功!<br>";
//插入数据
$conn->exec("INSERT INTO student VALUES (1, 'Insert By PHP');");
echo "记录插入成功!<br>";
?>
得到如下反馈:
使用phpMyAdmin
组件可以查看相关数据。
可以看到,数据库创建、基本表创建、数据插入操作均成功。创建changedViaPHP.php
,并输入如下代码:
<?php
$servername = "mydb"; // 上述的数据库容器名
$username = "root";
$password = $_ENV["MYSQL_ROOT_PASSWORD"];
try {
$conn = new PDO("mysql:host=$servername;", $username, $password);
echo "连接成功<br>";
}
catch(PDOException $e)
{
echo $e->getMessage();
}
//修改数据
$conn->exec("use phpdb;");
$conn->exec("update student set name='Changed By PHP' where id = 1;");
echo "修改成功<br>";
?>
同样通过URL访问web服务,可得如下现象:
并使用phpMyAdmin
验证:
创建deleteByPhp.php
,并输入如下代码:
<?php
$servername = "mydb"; // 上述的数据库容器名
$username = "root";
$password = $_ENV["MYSQL_ROOT_PASSWORD"];
try {
$conn = new PDO("mysql:host=$servername;", $username, $password);
echo "连接成功<br>";
}
catch(PDOException $e)
{
echo $e->getMessage();
}
//修改数据
$conn->exec("use phpdb;");
$conn->exec("delete from student where id = 1;");
echo "删除成功<br>";
?>
执行,并在phpMyAdmin
中查看:
至此,本次实验成功完成。
问题
1、第一次写docker-compose.yml
并部署时,出现如下错误。根据提示可知,yml文件扫描错误,容易推断出是语法错误。
root@docker01:/usr/local/myLNMP# docker-compose up
ERROR: yaml.scanner.ScannerError: mapping values are not allowed here
in "./docker-compose.yml", line 2, column 9
文章指出,在编写docker-compose.yml
时,要求每个冒号和每个-
符号后面必须有一个空格。
2、使用docker-compose up
命令部署项目时,定制PHP出现总是下载不了的情况。卡在Get:5 http://deb.debian.org/debian buster/main amd64 Packages [7907 kB]
动不了。
在PHP的Dockerfile中添加COPY sources.list /etc/apt
,并在上下文中添加sources.list
以更改软件源后,才能成功解决。
sources.list的内容如下:
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
3、在使用docker-compose up
命令部署项目的最后,出现了如下问题:
根据Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use
可知,端口已占用。这才想起Ubuntu中的本地MySQL服务仍开启中,使用service mysql stop
将它关闭后,就能正确部署了。
4、使用nginx服务器访问php业务时,出现SQLSTATE[HY00O] [2002] No such file or directory
错误。
出现这个问题主要是nginx的配置文件错误,注释的地方出错的关键。
...
server {
listen 80;
server_name localhost;
...
location / {
root /usr/share/nginx/myhtml;
index index.html index.htm;
}
...
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /var/www/myphp;
fastcgi_pass myphp:9000;
# 容器名:端口号,原句为127.0.0.1,修改的原因是容器ip并非127.0.0.1
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 原句为 fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
...
时间开销
事项 | 耗时(小时) |
---|---|
了解docker-compose | 3 |
编写Dockerfile和docker-compose.yml | 1 |
因网络问题部署失败 | 2 |
nginx与php连接排错 | 0.5 |
记录过程 | 2.5 |
总耗时 | 9 |
感想
感受到了docker虚拟化技术的强大,部署项目时足够的快速,比之前在物理机上效率高得多;遇到的问题就当是经验的积累吧。