第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的相关配置。需要注意的配置选项是rootfastcgi_passfastcgi_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虚拟化技术的强大,部署项目时足够的快速,比之前在物理机上效率高得多;遇到的问题就当是经验的积累吧。

posted @ 2020-05-04 17:57  rrmmoo  阅读(183)  评论(0编辑  收藏  举报