前序说明
对 docker 的基本用法有一定的了解,理解docker中的“容器、镜像、Dockerfile”之间的关系
1.分别从官方镜像仓库拉取 php、nginx、redis 的镜像
默认都是使用的最新版本,如果要使用特别版本,请自行搜索相应的版本再执行pull操作。
[root@master ~]# docker pull redis:6.0.6
...
[root@master ~]# docker pull nginx:1.19.1
...
[root@master ~]# docker pull php:7.3-fpm-alpine
...
[root@master ~]# docker image ls // 查看拉取的3个镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
php 7.3-fpm-alpine 5771742726c9 3 months ago 75.1MB
nginx 1.19.1 08393e824c32 3 months ago 132MB
redis 6.0.6 1319b1eaa0b7 3 months ago 104MB
2. 新建网络配置
注意: --subnet
指定的网段不能和虚拟机或主机所在的网段冲突!!!
[root@master ~]# docker network create --subnet=172.100.100.0/24 lrnp // 新建网络连接并且指定了网段并且命名为:“lrnp”
65bf9c1ea4b5bc54c0c3ed2e0931bfc1f666fb538d177220703afda7c52578ed
[root@master ~]# docker network ls // 查看全部的网络列表
NETWORK ID NAME DRIVER SCOPE
1c39dbef46f6 host host local
`65bf9c1ea4b5 lrnp bridge local`
...
基本配置列表:
容器名 | 镜像名称 | 挂载目录 | 端口映射 | ip地址 |
---|---|---|---|---|
nginx_compose | nginx_image_lrnp | /home/docker/lrnp/nginx/conf:/conf | 82:80 | 172.100.100.110 |
php_compose | php_image_lrnp | /home/docker/lrnp/php/www:/www | 9002:9000 | 172.100.100.120 |
redis_compose | redis_image_lrnp | /home/docker/lrnp/redis/data:/data | 6380:6379 | 172.100.100.130 |
3. nginx
3.1 测试nginx是否正常运行
[root@master ~]# docker run -it --rm -p 5200:80 nginx:1.19.1 // 运行一个临时容器,端口映射宿主机器的 5200 端口
....
..
/docker-entrypoint.sh: Configuration complete; ready for start up
测试:
例如,我的虚拟机本地ip是 “192.168.206.100”,浏览器访问:http://192.168.206.100:5200,打印:
如上图,则说明nginx镜像正常工作。
注意:要确保宿主机的 5200 端口是开放的。
[root@master ~]# firewall-cmd --add-port=5200/tcp --zone=public --permanent // 开放端口
[root@master ~]# firewall-cmd --reload // 重启防火墙
3.2 通过Dockerfile构建nginx镜像
3.2.1 编辑nginx镜像的 Dockerfile 文件
这里我使用的在已有的nginx镜像基础上新建自己的镜像,还有另外一种方式,就是通过安装包在Dockerfile 文件里面重新安装nginx,这种方式比较繁琐且构建出来的镜像体积较大,这里就不使用了。
文件:/home/docker/lrnp/nginx/Dockerfile
FROM nginx:1.19.1
# 新建文件夹 /conf
RUN mkdir /conf
# 声明匿名卷
VOLUME /data
# 拷贝自定义的 nginx.conf 配置文件到容器的 `/conf` 目录下
COPY ./conf/nginx.conf /conf
# 定义工作目录(进入容器时,默认打开的目录)
WORKDIR /conf
# 声明端口
EXPOSE 80
# 容器启动的时候执行,在docker run当中是会被其他命令替代的
# CMD ["/usr/local/nginx/sbin/nginx", "-c", "/conf/nginx.conf", "-g", "deame off;"]
# 执行一条指令 (按照自定的配置重启nginx)
ENTRYPOINT ["/usr/sbin/nginx", "-c", "/conf/nginx.conf", "-g", "daemon off;"]
注意:
- 首先这个Dockerfile镜像是根据官方镜像 nginx:1.9.1 改变而来,镜像里面的一些环境变量路径与软件包安装的指令路径可能不一致,需以镜像中的执行路径为准,如: nginx:1.9.1 中的nginx指令执行路径为 /usr/sbin/nginx。
- 需要指定nginx镜像的启动配置文件(由于需要配置php-fpm端口监听、转发),需自定义一个
nginx.conf
文件,具体如下:
文件:/home/docker/lrnp/nginx/conf/nginx.conf
user root;
worker_processes 1;
events {
worker_connections 1024;
}
error_log /data/error.log;
http {
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout 65;
server {
listen 80;
access_log /usr/local/nginx/logs/$host main;
location / {
# php-fpm容器的目录
root /home/docker/lrnp/php; # ★★★ 此处是 php 容器的所在目录,也可以自定义其他目录
default_type text/html;
}
location ~ \.php/?.* {
default_type text/html;
# 指定的php-fpm容器根路径地址中的目录,为:/home/docker/lrnp/php/www
root /www;
fastcgi_index index.php;
# docker network 所建立的网络桥接网络地址 php容器端口
fastcgi_pass 172.100.100.120:9000; # ★★★ 此处的ip为上述表格中注明的ip,端口为php-fpm默认的9000端口
#为php-fpm指定的根目录
fastcgi_param SCRIPT_FILENAME $DOCUMENT_ROOT$fastcgi_script_name;
#注意是容器当中的位置
#定义变量 $path_info ,用于存放pathinfo信息
set $path_info "";
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
#将文件地址赋值给变量 $real_script_name
set $real_script_name $1;
#将文件地址后的参数赋值给变量 $path_info
set $path_info $2;
}
#配置fastcgi的一些参数
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
#include /usr/local/nginx/conf/fastcgi_params;
include /etc/nginx/fastcgi_params; # ★★★ 此处修改为 nginx:1.19.1 容器中的配置文件目录
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
3.2.2 利用编辑好的Dockerfile文件生成nginx镜像
完成上述配置之后,在Dockerfile文件所在的目录下执行镜像生成:
[root@master nginx]# cd /home/docker/lrnp/nginx
[root@master nginx]# docker build -t nginx_image_lrnp . # 构建镜像
Sending build context to Docker daemon 6.144kB
Step 1/7 : FROM nginx:1.19.1
....
Step 7/7 : ENTRYPOINT ["/usr/sbin/nginx", "-c", "/conf/nginx.conf", "-g", "daemon off;"]
---> Running in 41c96172378a
Removing intermediate container 41c96172378a
---> 3b73f4017de8
Successfully built 3b73f4017de8
Successfully tagged nginx_image_lrnp:latest
[root@master nginx]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx_image_lrnp latest 15463e78f16f 3 hours ago 132MB
......
到此,nginx的镜像配置完成,其文件目录格式大致为如下:
4. php
4.1 编辑Dockerfile文件
这里基于 php:7.3-fpm-alpine 构建我们需要的镜像文件,Dockerfile文件内容如下:
文件:/home/docker/lrnp/php/Dockerfile
FROM php:7.3-fpm-alpine
# Version
ENV PHPREDIS_VERSION 4.0.0
# Libs
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add \
curl \
vim \
wget \
git \
openssl-dev\
zip \
unzip \
g++ make autoconf
# docker方式安装PDO extension # 安装扩展
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
&& docker-php-ext-install pdo_mysql \
&& docker-php-ext-install pcntl \
&& docker-php-ext-install sysvmsg
# Redis extension
RUN wget http://pecl.php.net/get/redis-${PHPREDIS_VERSION}.tgz -O /tmp/redis.tar.tgz \
&& pecl install /tmp/redis.tar.tgz \
&& rm -rf /tmp/redis.tar.tgz \
&& docker-php-ext-enable redis
# 修改php.ini的文件 extension=redis.so
# 暴露端口,此处的端口,需要跟之前表格的端口一致
EXPOSE 9000
#设置工作目录(进入php-fpm容器后默认进行的文件夹目录)
WORKDIR /www
4.2 生成php镜像
[root@master php]# docker build -t php_image_lrnp . # 执行构建
Sending build context to Docker daemon 4.096kB
Step 1/7 : FROM php:7.3-fpm-alpine
.......
Step 7/7 : WORKDIR /www
---> Using cache
---> 16f6af57a69f
Successfully built 16f6af57a69f
Successfully tagged php_image_lrnp:latest
生成完成,可见按照上传Dockerfile文件配置的内容,已经php-fpm已经安装了一些必要的php扩展,其中包括 redis 扩展;其目录格式大致为:
5. redis
5.1 生成镜像前的准备
由于redis服务在启动时,需要redis.conf
的配置文件(默认镜像中也有配置文件,但是我们大多数时候,需要镜像按照我们自己的配置来启动),并且redis运行时会产生数据,所以需要声明数据挂载点,否则当redis容器退出时,则在容器中产生的数据也会随着退出而删除(这里在Dockerfile里面我们暂不声明挂载点)。
5.1.1 编辑 redis.conf 文件
# Redis configuration file example.
#
# Note that in order to read the configuration file, Redis must be
# started with the file path as first argument:
#
# ./redis-server /path/to/redis.conf
# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include /path/to/local.conf
# include /path/to/other.conf
################################## MODULES #####################################
# Load modules at startup. If the server is not able to load modules
# it will abort. It is possible to use multiple loadmodule directives.
#
# loadmodule /path/to/my_module.so
# loadmodule /path/to/other_module.so
################################## NETWORK #####################################
# By default, if no "bind" configuration directive is specified, Redis listens
# for connections from all the network interfaces available on the server.
# It is possible to listen to just one or multiple selected interfaces using
# the "bind" configuration directive, followed by one or more IP addresses.
#
# Examples:
#
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1 ::1
#
# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the
# internet, binding to all the interfaces is dangerous and will expose the
# instance to everybody on the internet. So by default we uncomment the
# following bind directive, that will force Redis to listen only into
# the IPv4 loopback interface address (this means Redis will be able to
# accept connections only from clients running into the same computer it
# is running).
#
# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES
# JUST COMMENT THE FOLLOWING LINE.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# bind 127.0.0.1
# Protected mode is a layer of security protection, in order to avoid that
# Redis instances left open on the internet are accessed and exploited.
#
# When protected mode is on and if:
#
# 1) The server is not binding explicitly to a set of addresses using the
# "bind" directive.
# 2) No password is configured.
#
# The server only accepts connections from clients connecting from the
# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain
# sockets.
#
# By default protected mode is enabled. You should disable it only if
# you are sure you want clients from other hosts to connect to Redis
# even if no authentication is configured, nor a specific set of interfaces
# are explicitly listed using the "bind" directive.
protected-mode no
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379
# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 511
# Unix socket.
#
# Specify the path for the Unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
# unixsocket /tmp/redis.sock
# unixsocketperm 700
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
# TCP keepalive.
#
# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence
# of communication. This is useful for two reasons:
#
# 1) Detect dead peers.
# 2) Take the connection alive from the point of view of network
# equipment in the middle.
#
# On Linux, the specified value (in seconds) is the period used to send ACKs.
# Note that to close the connection the double of the time is needed.
# On other kernels the period depends on the kernel configuration.
#
# A reasonable value for this option is 300 seconds, which is the new
# Redis default starting with Redis 3.2.1.
tcp-keepalive 300
################################# GENERAL #####################################
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no
# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
# supervised no - no supervision interaction
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SO