内容来源为六星教育,这里仅作为学习笔记
lnrp环境构建
构建镜像
nginx的dockerfile
FROM centos:centos7
RUN mkdir /data && mkdir /conf
RUN groupadd -r nginx && useradd -r -g nginx nginx
#修改时区 RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
ARG PHP_VERSION=7.2
#添加centos源(先下载wget)
COPY ./epel-7.repo /etc/yum.repos.d/epel.repo
#COPY
#RUN yum install -y wget
#RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum update -y \
&& yum clean all \
&& yum makecache \
&& yum -y install gcc gcc-c++ autoconf automake make zlib zlib-devel net-tools openssl* pcre* wget \
&& yum clean all && rm -rf /var/cache/yum/*
#声明匿名卷
VOLUME /data
COPY ./nginx-1.14.1.tar.gz /data/nginx-1.14.1.tar.gz
RUN cd /data \
&& tar -zxvf nginx-1.14.1.tar.gz \
&& cd nginx-1.14.1 \
&& ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx \
&& make && make install && rm -rf /data/nginx-1.14.1.tar.gz && rm -rf /data/nginx-1.14.
COPY ./conf/nginx.conf /conf
#全局使用nginx,软链接
RUN ln -s /usr/local/nginx/sbin/* /usr/local/sbin
#进入容器时默认打开的目录
WORKDIR /conf
#声明端口
EXPOSE 80
#容器启动的时候执行,在docker run过程当中是会被其他指令替代
#CMD ["/usr/local/nginx/sbin/nginx","-c","/conf/nginx.conf","-g","daemon off;"]
#执行一条指
# ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-c","/conf/nginx.conf","-g","daemon off;"]
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
#设置工作目录
WORKDIR /www
redis的dockerfile
FROM centos:centos7
RUN groupadd -r redis && useradd -r -g redis redis
RUN mkdir data ;\
yum update -y ; \
yum -y install gcc automake autoconf libtool make wget epel-release gcc-c++;
COPY ./redis-5.0.7.tar.gz redis-5.0.7.tar.gz
RUN mkdir -p /usr/src/redis; \
tar -zxvf redis-5.0.7.tar.gz -C /usr/src/redis; \
rm -rf redis-5.0.7.tar.gz; \
cd /usr/src/redis/redis-5.0.7 && make ; \
cd /usr/src/redis/redis-5.0.7 && make install
COPY ./conf/redis.conf /usr/src/redis/redis-5.0.7/redis.conf
EXPOSE 6379
ENTRYPOINT ["redis-server", "/usr/src/redis/redis-5.0.7/redis.conf"]
或者直接 docker pull redis:6.0-rc-alpine
构建镜像跳过
构建构建容器
保存容器的数据卷
[root@localhost /]# mkdir docker
[root@localhost /]# mkdir docker/images
[root@localhost /]# mkdir docker/images/data/
[root@localhost /]# mkdir docker/images/data/php
[root@localhost /]# mkdir docker/images/data/nginx
[root@localhost /]# mkdir docker/images/data/redis
[root@localhost /]# mkdir docker/images/data/php/www
[root@localhost /]# mkdir docker/images/data/nginx/conf
构建容器
配置连接测试
注意redis.conf配置文件
#bind 127.0.0.1
protected-mode no
注意nginx.conf配置文件
user root;
worker_processes 1;
events {
worker_connections 1024;
}
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 / {
root /www;
default_type text/html;
}
location ~ \.php/?.* {
default_type text/html;
#做php-fpm 配置,注意地址
root /www;
#php-fpm容器当中的路径,不是nginx容器路径
fastcgi_index index.php;
fastcgi_pass 172.17.0.2:9000; #php容器端口
#为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;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
需要注意的是nginx.conf中的 fastcgi_pass 172.17.0.2:9001; #php容器端口
这行配置
中的 172.17.0.2
是宿主机ip
对应的PHP文件放置于: /docker/images/data/php/www
index.php文件内容:
<?php
$redis = new Redis();
$redis->connect('192.168.169.160', 6379);//serverip port
$redis ->set( "test" , "Hello World");
echo $redis ->get( "test");
?>
注意访问的地址是 http://192.168.169.160:81/index.php
需要带上 index.php
docker文件结构
- 为什么系统镜像那么小呢? 因为docker镜像在运行的时候直接使用docker宿主机器的kernel,Linux操作系统由内核空间和用户空间组成
内核空间是kernel,用户空间是rootfs, 不同Linux发行版的区别主要是rootfs.比如 Ubuntu 14.04 使用 upstart 管理服务,apt 管理软件包; 而 CentOS 7 使用 systemd 和 yum。这些都是用户空间上的区别,Linux kernel 差别不大。所以 Docker 可以同时支持多种 Linux 镜像, 模拟出多种操作系统环境。
- 镜像文件是分层存储的,我们可以通过docker history 命令查看到镜像的历史,也就是层
启动镜像的时候,一个新的可写层会加载到镜像的顶部。这一层通常称为“容器层”, 之下是“镜像层”。 容器层可以读写,容器所有发生文件变更写都发生在这一层。镜像层read-only,只允许读取。
Container最上面是一个可写的容器层,以及若干只读的镜像层组成,Container的数据就存放在这些层中,这样的分层结构最大的特性是Copy-OnWrite(写时复制):
- 新数据会直接存放在最上面的Container层。
- 修改现有的数据会先从Image层将数据复制到容器层,修改后的数据直接保存在Container层,Image层保持不变。
- 启动的容器会占用大量空间吗
创建镜像的时候,分层可以让docker只保存我们添加和修改的部分内容。其他内容基于base镜像,不需要存储,读取base镜像即可。如此,当我 们创建多个镜像的时候,所有的镜像共享base部分。节省了磁盘空间
docker通过一个叫做copy-on-write (CoW) 的策略来保证base镜像的安全性,以及更高的性能和空间利用率
简单的说,启动容器的时候,最上层容器层是可写层,之下的都是镜像层,只读层。
当容器需要读取文件的时候:
从最上层镜像开始查找,往下找,找到文件后读取并放入内存,若已经在内存中了,直接使用。(即,同一台机器上运行的docker容器共享 运行时相同的文件)。
当容器需要添加文件的时候:
直接在最上面的容器层可写层添加文件,不会影响镜像层。
当容器需要修改文件的时候:
从上往下层寻找文件,找到后,复制到容器可写层,然后,对容器来说,可以看到的是容器层的这个文件,看不到镜像层里的文件。容器在 容器层修改这个文件。
当容器需要删除文件的时候:
从上往下层寻找文件,找到后在容器中记录删除。即,并不会真正的删除文件,而是软删除。综上,Docker镜像通过分层实现了资源共享,通过copy-on-write实现了文件隔离。
docker网络模式
docker安装后,默认会创建下面三种网络类型
可以通过 --network bridge 指定网络类型
bridge:桥接网络
默认情况下启动的Docker容器,都是使用 bridge,Docker安装时创建的桥接网络,每次Docker容器重启时,会按照顺序获取对应的IP地址,这个就导致重启下,Docker的IP地址就变
从上面的网络模型可以看出,容器从原理上是可以与宿主机乃至外界的其他机器通信的。同一宿主机上,容器之间都是连接掉docker0这个网桥上的,它可以作 为虚拟交换机使容器可以相互通信。然而, 由于宿主机的 IP地址与容器的IP地址均不在同一个网段,不足以使宿主机以外的网络主动发现容器的存在。为了使外 界可以方位容器中的进程,docker采用了端口绑定的方式,也就是通过iptables的NAT, 将宿主机上的端口端口流量 转发到容器内的端口上
在宿主机上,可以通过iptables -t nat -L -n,查到一条DNAT规则:
bridge模式的容器与外界通信时,必定会占用宿主机上的端口,从而与宿主机竞争端口资源,对宿主机端口的管理会是一个比较大的问题。同时,由于容 器与外界通信是基于三层上iptables NAT,性能和效率上的损耗是 可以预见的
none
无指定网络 使用 --network=none ,docker 容器就不会分配局域网的IP
host
主机网络 使用 --network=host,此时,Docker 容器的网络会附属在主机上,两者是互通的。 例如,在容器中运行一个Web服务,监听8080端口,则主 机的8080端口就会自动映射到容器中
弊端:
1)最明显的就是容器不再拥有隔离、独立的网络栈。容器会与宿主机竞争网络栈的使用,并且容器的崩溃就可能导致宿主机崩溃,在生产环境中,这种 问题可能是不被允许的。
2)容器内部将不再拥有所有的端口资源,因为一些端口已经被宿主机服务、bridge模式的容器端口绑定等其他服务占用掉了
指定自定义网络
因为默认的网络不能制定固定的地址,所以我们将创建自定义网络,并指定网段:192.168.1.0/24 并命名为mynetwork,指令如下:
~ docker network create --subnet=192.160.1.0/24 mynetwork
~ docker run -itd --network=redis-network --ip 192.168.1.10 --name dockerName imagesName
~ docker network ls
~ docker network rm mynetwork
注意:这个网络段不要和宿主机的网络端冲突,不然会容易对宿主机产生影响