一个最终的应用通常需要组装多个容器提供的多个服务。以web服务为例,需要完成web服务器、数据库、开发程序等服务的组装,典型的如LAMP(Linux+Apache+Mysql+PHP)或LNMP(Linux+Nginx+Mysql+PHP)。Docker compose是作为定义和运行多容器的工具,用户可以使用 YML 文件来配置应用程序需要的所有服务。本次作业需要各位实践Docker compose,各位可以在第二次实践作业的基础之上开展,要求如下:
一、完成Docker-compose的安装
1.Linux 上我们可以从 Github 上下载它的二进制包来使用,但是速度会有点慢就换另一个源
sudo curl -L "https://get.daocloud.io/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
2.将可执行权限应用于二进制文件:
sudo chmod +x /usr/local/bin/docker-compose
3.创建软链:
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
4.测试是否安装成功:
docker-compose --version
注意: 对于 alpine,需要以下依赖包: py-pip,python-dev,libffi-dev,openssl-dev,gcc,libc-dev,和 make。
Alpine是什么呢?
Alpine Linux是一个面向安全的轻型的Linux发行版。
Alpine Linux采用了 musl libc 和 busybox以减小系统的体积和运行时资源消耗。
在保持瘦身的同时,Alpine Linux还提供了自己的包管理工具apk。
关键的是,相比于其他Linux的Docker镜像,它的容量非常小,只有5MB。
二、Dockerfile编写
要求:
LNMP/LAMP选择一种;
分别构建web、php应用、数据库等镜像服务,php镜像亦有提供php:
提示:php连接数据库需要安装必要的核心扩展部件(PHP Core Extensions)安装方法可参考官方镜像介绍。
选择LNMP
1.创建dockerfile_nginx:
FROM nginx:latest
EXPOSE 8010
2.创建dockerfile_php:
FROM php:7.4-fpm
RUN apt-get update && apt-get install -y
libfreetype6-dev
libjpeg62-turbo-dev
libpng-dev
&& docker-php-ext-install pdo_mysql
&& docker-php-ext-configure gd --with-freetype --with-jpeg
&& docker-php-ext-install -j$(nproc) gd
3.创建dockerfile_mysql:
FROM mysql:5.7
ENV MYSQL_ROOT_PASSWORD 123456
ENV MYSQL_ALLOW_EMPTY_PASSWORD no
4.创建dockerfile-phpmyadmin
FROM phpmyadmin/phpmyadmin
EXPOSE 8050
5.创建index.html
6.创建default.conf
server {
listen 8010; #监听8010端口
server_name localhost; #定义使用www.xx.com访问
location / { #默认请求
root /home/docker-web/html; #定义服务器的默认网站根目录位置
index index.html index.htm; #定义首页索引文件名称
}
#error_page 404 /404.html; #定义错误提示页面
# redirect server error pages to the static page /50x.html #重定向服务器错误页面
error_page 500 502 503 504 /50x.html; #定义错误提示页面
location = /50x.html {
root /usr/share/nginx/html;
}
location ~ .php$ { #通过PHP脚本sphp:9000的FastCGI服务器监听
root /home/docker-web/php; #修改工作目录
fastcgi_pass sphp:9000; #修改为容器名
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
文件结构如图:
三、使用Compose实现多容器运行机制
编写compose文件,完成上述LNMP/LAMP的微服务组合部署。
参考资料:Get started with Docker Compose
创建docker-compose.yml
version: "3"
services:
nginx:
image: snginx_image #指定镜像名
container_name: snginx #指定容器名
build:
context: .
dockerfile: dockerfile_nginx #指定dockerfile文件
ports:
- "80:8010" #修改端口映射
volumes:
- ./web:/home/docker-web/html #挂载容器卷,本地/容器内修改文件后,另一方都会同步更新;
- ./default.conf:/etc/nginx/conf.d/default.conf #挂载配置文件
php:
image: sphp_image
container_name: sphp
build:
context: .
dockerfile: dockerfile_php
environment:
MYSQL_PASSWORD: 123456 #设置好环境变量,在php代码中使用变量名直接引用
volumes:
- ./web:/home/docker-web/php #挂载工作目录到本机web目录
mysql:
image: mysql_image
container_name: mysql
build:
context: .
dockerfile: dockerfile_mysql
ports:
- "3306:3306"
volumes:
- ./mysql_data:/var/lib/mysql #挂载容器卷,实现数据同步,防止数据丢失
phpmyadmin:
image: myphpmyadmin_image
container_name: myphpmyadmin
build:
context: .
dockerfile: dockerfile_phpmyadmin
ports:
- "8050:80" # phpmyadmin默认监听80
environment:
PMA_HOST: mysql #指定mysql服务所在的host
Localhost 打开了docker-compose web index.html
Localhost:8050 打开了phpmyadmin
四、服务测试
要求和提示:
包括但不限于测试数据库连接、数据库新建、表新建、表记录的插入修改和删除是否成功(pdo或mysqli均可);
相关测试代码可直接参考PHP与MySQL的教程。
https://www.runoob.com/php/php-mysql-connect.html
PDO 应用在 12 种不同数据库中, MySQLi 只针对 MySQL 数据库
1.测试数据库连接
(1)编辑index.php文档
<?php
$servername = "mysql";
$username = "root";
$password = "123456";
try {
$conn = new PDO("mysql:host=$servername", $username, $password);
echo "连接成功";
}
catch(PDOException $e)
{
echo $e->getMessage();
}
(2)测试
2.数据库新建
(1)编辑index.php文档
<?php
$servername = "mysql";
$username = "root";
$password = "123456";
try {
$conn = new PDO("mysql:host=$servername", $username, $password);
// 设置 PDO 错误模式为异常
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "CREATE DATABASE myDBPDO";
// 使用 exec() ,因为没有结果返回
$conn->exec($sql);
echo "数据库创建成功<br>";
}
catch(PDOException $e)
{
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
?>
(2)测试
3.表新建
(1)编辑index.php文档
<?php
$servername = "mysql";
$username = "root";
$password = "123456";
$dbname = "myDBPDO";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// 设置 PDO 错误模式,用于抛出异常
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 使用 sql 创建数据表
$sql = "CREATE TABLE stu (
ID INT(9) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(30) NOT NULL,
MAJOR VARCHAR(30) NOT NULL
)";
// 使用 exec() ,没有结果返回
$conn->exec($sql);
echo "数据表 stu 创建成功";
}
catch(PDOException $e)
{
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
?>
(2)测试
4.表记录的插入
(1)编辑index.php文档
<?php
$servername = "mysql";
$username = "root";
$password = "123456";
$dbname="myDBPDO";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 开始事务
$conn->beginTransaction();
// SQL 语句
$conn->exec("INSERT INTO stu (ID, NAME, MAJOR)
VALUES ('031702507', 'hh', 'CS')");
$conn->exec("INSERT INTO stu (ID, NAME, MAJOR)
VALUES ('03172508', 'xs', 'CS')");
$conn->exec("INSERT INTO stu (ID, NAME, MAJOR)
VALUES ('031702624', 'zz', CS')");
// 提交事务
$conn->commit();
echo "新记录插入成功";
}
catch(PDOException $e)
{
// 如果执行失败回滚
$conn->rollback();
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
?>
(2)测试
5.表记录的修改
(1)编辑index.php文档
<?php
$servername = "mysql";
$username = "root";
$password = "123456";
$dbname="myDBPDO";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// SQL 语句
$conn->exec("UPDATE stu SET MAJOR='Computer Science' WHERE ID=031702507");
echo "记录修改成功";
}
catch(PDOException $e)
{
// 如果执行失败回滚
$conn->rollback();
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
?>
(2)测试
6.表记录的删除
(1)编辑index.php文档
<?php
$servername = "mysql";
$username = "root";
$password = "123456";
$dbname="myDBPDO";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// SQL 语句
$conn->exec("DELETE FROM stu where ID=03172508");
echo "记录删除成功";
}
catch(PDOException $e)
{
// 如果执行失败回滚
$conn->rollback();
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
?>
(2)测试
五、选做
增加一个phpmyadmin容器,实现web端的数据库管理。
在上面二、就已经写了dockerfile_phpmyadmin和docker-compose.yml
(1)从localhost:8050端口进入
(2)查看myDBPDO数据库中的stu表
(3)表记录的插入
(4)表记录的修改
(5)表记录的删除
六、小结
1.主要问题和解决办法
问题1:
解决方法:因为YAML使用缩进表示层级关系;所以检查缩进关系。成功解决问题。
知识储备:
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过使用一个命令,就可以从 YML 文件配置中创建并启动应用程序需要的所有服务。
基本语法
大小写敏感;
使用缩进表示层级关系;
缩进不允许使用tab,只允许空格。缩进的空格数不重要,只要相同层级的元素左对齐即可;
'#'表示注释。
问题2:晚上下载的时候一直卡在pull phpmyadmin,甚至下了一晚上都还么下完。
解决方法:白天的时候添加多个国内镜像源,再试一次就好了。(得出神秘的结论,晚上不适合做实验
sudo vi /etc/docker/daemon.json
{"registry-mirrors":["https://docker.mirrors.ustc.edu.cn/","https://hub-mirror.c.163.com","https://registry.docker-cn.com"],}
systemctl restart docker.service
问题3:docker-compose up 完成后还是不能够访问
解决办法:重新检查一下前面写的dockerfile、yml、default.conf文件,发现映射端口80被两个服务占用,,将其中一个改成别的就可以了。
问题4:通过 phpinfo() 查看PDO是否安装成功:结果是失败的。
尝试:重新安装php:4.4-fpm还是一样
安装PDO,但是从phpinfo()看还是没变。
未解决,同学说并不影响就先放着了。
问题5:php连接mysql连接不上,查看容器运行状态发现mysql没有在运行,php连接mysql连接不上,查看容器运行状态发现mysql没有在运行。
解决方法:使用docker logs mysql发现问题在与mysql的dockerfile中没设置root密码。在dockerfile_mysql中添加
ENV MYSQL_ROOT_PASSWORD 123456
ENV MYSQL_ALLOW_EMPTY_PASSWORD no
问题6:解决了问题5后,访问localhost/index.php出现SQLSTATE[HY000][2002]Connection refused
解决办法:原因是数据库没有启动
service mysql start
2.感想
记录完成作业所花的时间:看资料一个早上加一个下午,实际操作一个晚上加一早上
每次开始做这个作业之前都得深呼吸,告诉自己莫生气莫着急。当第一遍,发现phpmyadmin的dockerfile文件是空的从而导致docker-compose up停止,一切还觉得能接受能接受。然后一个晚上都在慢慢地pull phpmyadmin,心态逐渐崩塌,无数次痛锤自己为什么第一次不好好检查一下。中间无数次的docker-compose down,意志又逐渐坚强。
很多时候其实不是不懂那个知识点,但是实操总会出错。有时候也确实是不懂那个知识点,上网查的话也不知道具体该查什么,这时候就该感谢热心解决问题的同学,解决了困扰我一早上的问题。总之还是多看多学多问。