编写Dockerfile

最近在部署项目事,想做一个基于ubuntu20.04,搭建nginx + php8.*的镜像。但是在制作的过程中遇到了很多坑,记录下来供后续参考学习。

修改镜像过程大概分为了6个模块:

  1. 模块一:对ubuntu 20.04官方镜像重新构造。
  2. 模块二:在基础镜像添加php8.*的源
  3. 模块三:安装nginx、php以及相关依赖。
  4. 模块四:设置nginx、php配置文件
  5. 模块五:编写nginx、php-fpm8.*启动脚本文件
  6. 模块六:镜像打包与验证。

1、创建Dockerfile文件,基于ubuntu20.04官方镜像编写。

创建项目目录、创建Dockerfile文件。

#创建项目目录

mkdir laravel-crm

#切换至项目目录

cd laravel-crm

#创建Dockerfile文件

touch Dockerfile

touch nginx.conf

touch php.ini

touch phpinfo.php

对ubuntu 20.04官方镜像重新构造,使用LABEL 参数设置了运营人员信息。使用apt-get安装软件时,ubuntu20.04 系统自带的源太慢,将apt-get源修改为国内任意可用源地址,这里以清华大学源为例。

使用sed -i 替换/etc/apt/sources.list 镜像,替换之后使用apt-get clean,apt-get update更新ubuntu20.40最新源地址,如以下代码所示。

# 基础镜像是 Ubuntu 20.04(可使用本地已存在的镜像作为基础)
FROM ubuntu:20.04

#镜像维护人员
LABEL maintainer="yangfan<834551859@qq.com>"

#ubuntu apt-get原镜像太慢了,替换国内的镜像,这里是以清华大学镜像为例。
RUN sed -i s:/archive.ubuntu.com:/mirrors.tuna.tsinghua.edu.cn/ubuntu:g /etc/apt/sources.list
RUN cat /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update

#设置服务器时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

2.在基础镜像添加php8.*的源

ubuntu 20.04本身的php版本最高时php7.4.,而要求是要安装php8.查阅相关安装资料,安装命令如下:

#命令一
apt-get install  ca-certificates apt-transport-https software-properties-common

#命令二
add-apt-repository ppa:ondrej/php

3.安装nginx、php以及相关依赖

#安装nginx 
RUN apt-get update \
    && apt-get install -y nginx \ 
    php8.2 php8.2-fpm php8.2-dev \
    php8.2-gd php8.2-curl php8.2-bz2 php8.2-bcmath \
    php8.2-imap php8.2-mysql php8.2-mbstring \
    php8.2-xml php8.2-zip php8.2-soap \
    php8.2-msgpack php8.2-igbinary php8.2-ldap \
    php8.2-redis php8.2-intl \
    && php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
    && apt-get -y autoremove \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*    

# nginx默认启动用户是www-data用户 www-data组,当php-fpm8.* 运行时生成php8.*-fpm.sock有权限

RUN mkdir -p /run/php && chown www-data:www-data /run/php

nginx默认启动用户是www-data用户 www-data组,因此需要给 /run/php文件夹授权,在php-fpm8. 运行时可以生成php8.-fpm.sock文件。

image.png

4.设置nginx、php配置文件

#将指定文件夹内容copy到容器里面

COPY nginx.conf /etc/nginx/nginx.conf

COPY php.ini /etc/php/8.2/fpm/php.ini


#创建工作目录文件夹
RUN mkdir -p /var/www/html
ADD start.sh /var/www/html
ADD . /var/www/html

5.编写nginx、php-fpm8.*启动脚本文件

Dockerfile文件中使用CMD就可以运行程序或者脚本文件,但是当一个Dockerfile出现多个CMD的时候,自上而下执行最后一个。我们期望在docker容器启动时,分别启动nginx、php-fpm8.*,则需要放在脚本文件里面进行启动。

#工作目录 
WORKDIR /var/www/html

#对外暴露端口
EXPOSE 80
EXPOSE 443
EXPOSE 9000

#CMD 指令指定在容器启动时执行的命令
#CMD ["sh","-c","php-fpm7.4"]

#CMD ["nginx","-g","daemon off;"]
CMD ["./start.sh"]

根据上面5个模块,最终Dockerfile脚本文件如下。

# 基础镜像是 Ubuntu 20.04(可使用本地已存在的镜像作为基础)
FROM ubuntu:20.04

#镜像维护人员
LABEL maintainer="yangfan<834551859@qq.com>"

#ubuntu apt-get原镜像太慢了,替换国内的镜像,这里是以清华大学镜像为例。
RUN sed -i s:/archive.ubuntu.com:/mirrors.tuna.tsinghua.edu.cn/ubuntu:g /etc/apt/sources.list
RUN cat /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update

#设置服务器时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 扩展依赖
RUN apt-get install -y \
    apt-utils \
    curl \
    git \
    apt-transport-https \
    software-properties-common \
    g++ \
    build-essential 


#ubuntu 20.04 apt 安装 PHP8.0
RUN add-apt-repository -y ppa:ondrej/php

RUN apt-get update \ 
    && apt-get install -y dialog \
    whiptail

#安装nginx 
RUN apt-get update \
    && apt-get install -y nginx \ 
    php8.2 php8.2-fpm php8.2-dev \
    php8.2-gd php8.2-curl php8.2-bz2 php8.2-bcmath \
    php8.2-imap php8.2-mysql php8.2-mbstring \
    php8.2-xml php8.2-zip php8.2-soap \
    php8.2-msgpack php8.2-igbinary php8.2-ldap \
    php8.2-redis php8.2-intl \
    && php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
    && apt-get -y autoremove \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*    

# nginx默认启动用户是www-data用户 www-data组,当php-fpm8.* 运行时生成php8.*-fpm.sock有权限

RUN mkdir -p /run/php && chown www-data:www-data /run/php


#将指定文件夹内容copy到容器里面

COPY nginx.conf /etc/nginx/nginx.conf

COPY php.ini /etc/php/8.2/fpm/php.ini


#创建工作目录文件夹
RUN mkdir -p /var/www/html
ADD start.sh /var/www/html
ADD . /var/www/html

RUN chmod +x /var/www/html/start.sh


#工作目录 
WORKDIR /var/www/html

#对外暴露端口
EXPOSE 80
EXPOSE 443
EXPOSE 9000

#CMD 指令指定在容器启动时执行的命令
#CMD ["sh","-c","php-fpm7.4"]

#CMD ["nginx","-g","daemon off;"]
CMD ["./start.sh"]

nginx.conf配置文件如下:

# 全局配置
user www-data;

worker_processes auto;

error_log /var/log/nginx/error.log warn;
 
events {
    worker_connections  1024;
}
 

# http 配置
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
 
    # 访问日志配置
    access_log /var/log/nginx/access.log;
 
    # 服务器块
    server {
        listen 80;
        server_name localhost;
        #laravel配置目录,根据自己项目需要,重新设置文件目录;
        root /var/www/html/public;
 
        location / {
            index index.php index.html;
            try_files $uri $uri/ /index.php?$query_string;

            if (!-e $request_filename){ 
               rewrite ^/(.*) /index.php last; 
            }

        }
 
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
             root /var/www/html/public;
        }


        location ~ \.php(.*)$ {
            fastcgi_pass   unix:/run/php/php8.2-fpm.sock;
            fastcgi_index  index.php;
            fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            fastcgi_param  PATH_INFO  $fastcgi_path_info;
            fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
            include        fastcgi_params;
            include        fastcgi.conf;
        }    
    }
}

php.ini配置文件,如下:

; Execution, size, upload
 max_input_time = 60
 max_execution_time = 60
 memory_limit = 256M
 post_max_size = 56M
 upload_max_filesize = 56M
 output_buffering = 4096
 realpath_cache_size = 4096k
 realpath_cache_ttl = 600
;
; ; Error
 log_errors = On
 error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
 display_errors = Off
 display_startup_errors = Off
;
; ; Security
 allow_url_fopen = Off
 allow_url_include = Off
 disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,
;
; ; Misc
 request_order = "GP"
 variables_order = "GPCS"
 register_argc_argv = Off
 short_open_tag = Off
 zend.assertions = -1
; [CLI Server]
 cli_server.color = On
; [Session]
 session.sid_bits_per_character = 5
 session.gc_divisor = 1000
 session.sid_length = 26
; [mysqlnd]
 mysqlnd.collect_statistics = Off
 mysqlnd.collect_memory_statistics = Off
; [opcache]
 opcache.enable=1
 opcache.memory_consumption=512
 opcache.interned_strings_buffer=64
 opcache.max_accelerated_files=32531
 opcache.validate_timestamps=0
 opcache.save_comments=1
 opcache.fast_shutdown=1

start.sh脚本如下:

#!/bin/bash

echo "------------nginx start-----"

cd /usr/sbin

pwd

policy-rc.d

php-fpm8.2 -D

nginx -g "daemon off;"

ps aux | grep nginx

ps aux | grep php-fpm
echo "------------nginx end -----"

phpinfo.php文件内容如下:

<?php
   phpinfo();
?>

6.镜像打包与验证。

在laravel-crm文件夹执行镜像打包命令,并验证镜像文件是否已生成。

docker build -t "yangfanubuntu:v1.4" .

使用 docker images 查看本机所有镜像,确实有一个名字叫yangfanubuntu:v1.4的镜像,说明自定义镜像文件已经生成。
image.png

使用yangfanubuntu:v1.4镜像创建容器
-p 指定端口号
-d 允许容器后台运行
--name 设置镜像名字

docker run -it -d -p 8088:80 --name=laravel-crm yangfanubuntu:v1.4

image.png

使用docker ps -a 查看是否生成laravel-crm容器

image.png

验证nginx + php8.*是否成功。
image.png


杨帆
28 声望3 粉丝