Linux云计算 |【第五阶段】CLOUD-DAY5

主要内容:

容器的镜像编排,commit简单镜像创建,Dockerfile制作服务镜像(语法、创建镜像)、创建复杂镜像(Docker微服务架构、示例:NGINX+PHP)、私有仓库

一、简单镜像创建

1、自定义镜像原理

① 镜像采用分层设计

Docker镜像采用分层设计,每一层都是一个只读的文件系统层。这些层可以被多个镜像共享,从而节省存储空间并提高镜像的构建效率。每一层都代表了对文件系统的增量修改。

② 创建读写层

当您启动一个容器时,Docker会在镜像的最上层添加一个读写层。这个读写层允许您在容器中进行修改,而不会影响底层的只读层。

③ 修改配置

在容器中,您可以进行各种自定义修改,例如安装软件包、修改配置文件、添加或删除文件等。这些修改都会记录在读写层中。

④ 重新打包(commit)

当您完成自定义修改后,可以使用 docker commit 命令将当前容器的读写层和底层的只读层打包成一个新的镜像。这个新镜像包含了您所做的所有修改。

2、使用Commit创建镜像

**原理:**使用 docker commit 命令可以将一个正在运行的容器的状态保存为一个新的镜像。这个过程包括将容器的读写层和底层的只读层打包成一个新的镜像层。

格式: docker commit 容器id 新镜像名称:标签

容器ID:您要提交的容器的ID。

新镜像名称:您要创建的新镜像的名称。

标签:新镜像的标签,通常用于版本控制。

**例如:**假设有一个正在运行的容器,其ID为 abcd1234,您希望将其保存为一个新的镜像,名称为 my-custom-image,标签为 v1.0。您可以使用以下命令:

docker commit abcd1234 my-custom-image:v1.0

**示例:**通过Commit创建(打包)自定义镜像

① 使用centos镜像启动容器

bash 复制代码
[root@docker-0001 ~]# docker run -it centos:latest

② 自定义修改:配置Yum源(华为云YUM源),安装软件

bash 复制代码
[root@6f239a4d0fc3 /]# rm -f /etc/yum.repos.d/*.repo
[root@6f239a4d0fc3 /]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.myhuaweicloud.com/repo/CentOS-Base-7.repo
[root@6f239a4d0fc3 /]# yum install -y net-tools vim-enhanced tree bash-completion iproute psmisc && yum clean all
[root@6f239a4d0fc3 /]# exit
exit

③ 创建自定义镜像(对容器进行打包制作新镜像)

bash 复制代码
[root@docker-0001 ~]# docker commit 6f239a4d0fc3 myos:latest
sha256:8ee6a9acdcd19ed70e78d74ead608fde5a4bdb12faa147f6fd3acd257179fb76

④ 验证镜像

bash 复制代码
[root@docker-0001 ~]# docker images
bash 复制代码
[root@docker-0001 ~]# docker run -it myos:latest    //基于新镜像运行容器
[root@183f4b606ff2 /]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
[root@docker-0001 ~]# docker history myos:latest    //查看容器制作历史

补充:打包完成新镜像后,可将制作镜像的容器删除,以及基于的centos镜像删除,都不会影响现有的新镜像;

bash 复制代码
[root@docker-0001 ~]# docker rm 6f239a4d0fc3
6f239a4d0fc3
[root@docker-0001 ~]# docker rmi centos:latest
Untagged: centos:latest

二、Dockerfile概述

Dockerfile 是一个文本文件,包含了一系列指令,用于定义如何构建 Docker 镜像。每个指令都会在镜像中创建一个新的层,从而实现分层构建。

1、docker commit 的局限性

虽然 docker commit 命令可以快速创建自定义镜像,但它有一些明显的局限性:

  • 难以管理复杂配置:对于复杂的镜像,例如需要设置默认的启动命令、环境变量、开放特定端口等,docker commit 很难满足需求。
  • 缺乏版本控制:使用 docker commit 创建的镜像缺乏版本控制,难以追踪和管理不同版本的镜像。
  • 不可重复性:每次使用 docker commit 创建的镜像都是基于当前容器的快照,难以保证每次构建的结果一致。

2、Dockerfile 的优势

Dockerfile 是一种更强大、更灵活的镜像制作方式,它允许您通过编写类似脚本的文件来定义镜像的构建过程。以下是 Dockerfile 的主要优势:

  • 可重复性:Dockerfile 允许您定义镜像的构建步骤,确保每次构建的结果一致。
  • 版本控制:Dockerfile 可以与版本控制系统(如 Git)结合使用,方便追踪和管理不同版本的镜像。
  • 复杂配置管理:Dockerfile 支持设置默认的启动命令、环境变量、开放端口等复杂配置,使得镜像的构建更加灵活和可控。
  • 依赖管理:Dockerfile 可以明确指定镜像的依赖关系,确保构建过程中所需的软件包和库都能正确安装。
  • 自动化构建:Dockerfile 可以与 CI/CD 工具集成,实现自动化构建和部署。

3、Dockerfile 的基本结构

1)FROM

指定构建镜像的基础镜像:所有 Dockerfile 都必须以 FROM 指令开始。

FROM ubuntu:20.04

2)LABEL

指定镜像的维护者信息:添加元数据,如维护者信息、版本号等。

LABEL maintainer="your-email@example.com"

3)ENV

设置环境变量:

ENV MY_VAR="my-value"

4)WORKDIR

指定工作目录:后续的 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指令都会在该目录下执行。

WORKDIR /app

5)COPY

将本地文件拷贝到镜像中:

COPY . /app

6)RUN

安装所需的软件包:在镜像中执行命令。每个 RUN 指令都会创建一个新的层。

RUN apt-get update && apt-get install -y \
    package1 \
    package2

7)EXPOSE

指定镜像需要暴露的端口:

EXPOSE 8080

8)CMD

设置默认的启动命令:一个 Dockerfile 中只能有一个 CMD 指令。

CMD ["python", "app.py"]

9)ADD

类似于 COPY,但支持从 URL 下载文件并解压缩 tar 文件。

ADD https://example.com/file.tar.gz /app/

10)ENTRYPOINT

设置容器启动时执行的命令,通常用于设置可执行文件。CMD 可以作为参数传递给 ENTRYPOINT

ENTRYPOINT ["python"]
CMD ["app.py"]

11)VOLUME

创建一个挂载点,用于持久化数据。

VOLUME /data

12)USER

设置运行后续指令的用户。

USER myuser

13)ARG

定义构建时传递的参数。

ARG MY_ARG="default-value"

14)ONBUILD

设置当该镜像被用作基础镜像时,自动执行的指令。

ONBUILD COPY . /app

4、使用 Dockerfile 构建镜像

工作流程:

① 创建目录(例如:mkdir mybuild);

② 在目录中编写Dockfile文件;

③ 生成镜像;

在编写好 Dockerfile 后,可以使用 docker build 命令来构建镜像:

  • 格式:docker build -t 镜像名称:标签 Dockerfile所在目录

    docker build -t my-custom-image:v1.0 .

  • -t 参数用于指定新镜像的名称和标签。

  • . 表示 Dockerfile 所在的当前目录。

  • CMD指令 可以查看 service 文件的启动命令 ExecStart(/lib/systemd/system/httpd.service)

  • ENV 环境变量查询服务文件中的环境变量配置文件 EnvironmentFile 指定的文件内容


示例:通过Dockerfile制作apache+php服务镜像

提前拷贝webhome.tar.gz到192.168.1.31(参考:/web_install/files/webhome.tar.gz)

bash 复制代码
[root@ecs-proxy ~]# scp /root/other/web_install/files/webhome.tar.gz 192.168.1.31:/root

① 创建并切换apache目录

bash 复制代码
[root@docker-0001 ~]# mkdir apache
[root@docker-0001 ~]# cp webhome.tar.gz /root/apache/  //需放到同Dockerfile相同目录
[root@docker-0001 ~]# cd apache

② 编写Dockerfile文件

bash 复制代码
[root@docker-0001 apache]# vim Dockerfile
FROM myos:latest                    //指定基础镜像myos:latest
RUN yum install -y httpd php        //执行命令:安装Apache、php服务
ENV LANG=C                          //设置环境变量
ADD webhome.tar.gz /var/www/html/   //ADD复制压缩包到镜像并自动解压
WORKDIR /var/www/html/              //指定工作目录
EXPOSE 80                           //声明开放的端口
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]    //容器启动命令(参考service文件)

③ 使用docker build对Dockerfile内容生成镜像

bash 复制代码
[root@docker-0001 apache]# docker build -t myos:httpd .   //【.】为Dockerfile所在目录
...
Successfully built 5adb6e780c95
Successfully tagged myos:httpd

④ 查看镜像,并基于myos: httpd镜像,启动容器并验证服务

bash 复制代码
[root@docker-0001 apache]# docker images
bash 复制代码
[root@docker-0001 ~]# docker run -itd myos:httpd    //启动容器并放入后台运行
73985edea99f5b80bf557dda8e8b663ef7650b24e28d56dfd957089515653117
[root@docker-0001 ~]# docker ps
bash 复制代码
[root@docker-0001 ~]# docker inspect 73985edea99f    //查看容器详细信息
...
                   "IPAddress": "172.17.0.3",    //查找到容器的IP
...

注意:使用docker inspect可以查看镜像或者容器的详细信息,只有容器中才会有IP信息;

bash 复制代码
[root@docker-0001 ~]# curl http://172.17.0.3/info.php   //验证服务
<pre>
Array
(
    [REMOTE_ADDR] => 172.17.0.1
    [REQUEST_METHOD] => GET
    [HTTP_USER_AGENT] => curl/7.29.0
    [REQUEST_URI] => /info.php
)
php_host:       73985edea99f
1229

三、复杂镜像创建

1、微服务架构介绍

微服务架构(Microservices Architecture)是一种软件架构风格,它将一个大型应用程序拆分为一组小型、独立的服务。每个服务都运行在自己的进程中,并通过轻量级机制(如 HTTP/REST 或消息队列)进行通信。每个服务都专注于完成一个特定的业务功能,并且可以独立开发、部署和扩展。

1)微服务架构与单体架构的区别

  • **单体架构:**传统的单体应用将所有功能打包在一个单一的代码库中,部署在一个单一的进程中。虽然开发和部署相对简单,但随着应用规模的扩大,单体应用会变得越来越复杂,难以维护和扩展。
  • **微服务架构:**微服务架构将应用拆分为多个核心功能,每个功能作为一个独立的服务运行。每个服务都可以独立开发、部署和扩展,从而解决了单体应用的复杂性问题。

2)微服务架构的优势:

高可扩展性: 每个服务都可独立扩展,根据需求增加或减少资源
出色的弹性: 微服务架构允许服务之间相互隔离,一个服务的故障不会影响整个应用
易于部署: 每个服务都可独立部署,减少了部署的风险和复杂性
易于访问: 每个服务都可通过标准化的接口(如 RESTful API)进行访问,便于集成和调用
更加开发: 微服务架构鼓励团队独立开发和维护各自的服务,提高了开发效率
**松耦合高内聚:**服务之间通过明确定义的接口进行通信,降低了耦合性,同时每个服务内部保持高内聚

3)微服务架构的核心思想:

微服务的核心思想是将应用服务"拆分"成多个核心功能。每个服务都应该是独立的、自治的,并且可以独立开发、测试、部署和扩展。

4)构建微服务的关键点:

  • **服务拆分:**理清各个服务之间的关系,确保每个服务都专注于一个特定的业务功能
  • **服务通信:**选择合适的通信机制(如 HTTP/REST、消息队列等),确保服务之间的松耦合和高内聚
  • **持续演进:**保持服务的持续演进,使服务能够快速、低成本地被拆分和合并,以快速响应业务的变化,持续迭代
  • **自动化工具:**利用自动化工具(如 CI/CD 工具)实现服务的自动化构建、测试和部署

5)Docker 与微服务架构:

Docker 是一种应用的管理模式,它通过容器化技术将每个服务封装在一个独立的容器中。每个容器承载一个服务,一台计算机可以同时运行多个容器,从而轻松模拟出复杂的微服务架构。Docker 的优势在于:

隔离性:每个容器都是独立的,互不干扰,确保服务的隔离性和安全性。

一致性:Docker 确保在开发、测试和生产环境中的一致性,减少了环境差异带来的问题。

快速部署:Docker 容器可以快速启动和停止,便于服务的快速部署和扩展。

资源利用率:Docker 容器共享主机操作系统的内核,提高了资源利用率。


示例:通过Dockerfile制作一个NGINX微服务 + PHP-FPM微服务

步骤1:制作php-fpm镜像

① 创建并切换php目录

bash 复制代码
[root@docker-0001 ~]# mkdir php ; cd php

② 编写Dockerfile文件

bash 复制代码
[root@docker-0001 php]# vim Dockerfile
FROM myos:latest                 //指定myos基础镜像
RUN yum install -y php-fpm       //运行命令:安装php软件包
EXPOSE 9000                      //声明开放的端口
CMD ["/usr/sbin/php-fpm","--nodaemonize"]   //容器启动命令(参考service文件)

③ 使用docker build对Dockerfile内容生成镜像

bash 复制代码
[root@docker-0001 php]# docker build -t myos:php-fpm .
...
Successfully built 6fad12240171
Successfully tagged myos:php-fpm

④ 基于myos:php-fpm镜像,启动容器并验证服务

bash 复制代码
[root@docker-0001 php]# docker run -itd myos:php-fpm     //启动容器并放入后台运行
b2bd2f88c33330c192ca34ec5b373e77dcea70bddbded5010899d35bccaf8182
[root@docker-0001 php]# docker ps     //查看运行的容器
bash 复制代码
[root@docker-0001 php]# docker exec -it b2bd2f88c333 /bin/bash    //进入容器
[root@b2bd2f88c333 /]# ss -nlptu | grep :9000     //查看监听端口
tcp    LISTEN     0      128    127.0.0.1:9000                  *:*                   users:(("php-fpm",pid=1,fd=6))

提示:容器启动命令CMD ["/usr/sbin/php-fpm","--nodaemonize"],可根据service文件查看,需要自行安装php-fpm软件包,查找到service启动文件;

步骤2:制作nginx镜像

提示:Nginx一般采用编译安装,在容器内编译不容易排错也不便于管理;根据Dockfile文件中的语法ADD可以将一个压缩包复制到容器内并自动解压释放特性,可以在外部编译Nginx并把编译好的程序目录打包,使用打包文件构建Nginx镜像服务;

注意:Nginx进程默认在后台运行,可以使用参数daemon off,强制进程在前台运行;

提前将所需软件包拷贝到192.168.1.31中(参考:other/nginx-1.12.2.tar.gz)

bash 复制代码
[root@ecs-proxy ~]# scp /root/other/nginx-1.12.2.tar.gz 192.168.1.31:/root

① 编译安装Nginx服务

bash 复制代码
[root@docker-0001 ~]# yum -y install gcc make pcre-devel openssl-devel  //安装依赖包
[root@docker-0001 ~]# useradd nginx   //创建Nginx用户
[root@docker-0001 ~]# tar -xf nginx-1.12.2.tar.gz
[root@docker-0001 ~]# cd nginx-1.12.2/
[root@docker-0001 nginx-1.12.2]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module
[root@docker-0001 nginx-1.12.2]# make && make install
[root@docker-0001 nginx-1.12.2]# ls /usr/local/nginx/
conf  html  logs  sbin

② 拷贝docker-images/目录下的测试文件info.html和info.php到nginx/html目录

bash 复制代码
[root@ecs-proxy ~]# scp /root/kubernetes/docker-images/info.* 192.168.1.31:/usr/local/nginx/html/

③ 将编译好的Nginx程序目录打包

bash 复制代码
[root@docker-0001 ~]# cd /usr/local/
[root@docker-0001 local]# tar -czf nginx.tar.gz nginx/

④ 制作nginx镜像

bash 复制代码
[root@docker-0001 ~]# mkdir nginx ; cd nginx
[root@docker-0001 nginx]# cp /usr/local/nginx.tar.gz .   //拷贝压缩文件到当前目录
[root@docker-0001 nginx]# ls
nginx.tar.gz
[root@docker-0001 nginx]# vim Dockerfile
FROM myos:latest                  //基于基础镜像myos:latest
RUN yum install -y pcre openssl && useradd nginx   //执行命令:安装依赖包和创建用户
ADD nginx.tar.gz /usr/local/      //ADD复制压缩包到镜像并自动解压
EXPOSE 80                         //声明开放端口
WORKDIR /usr/local/nginx/html    //指定工作目录
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]   //容器启动命令

补充:因为启动Nginx使用/usr/local/nginx/sbin/nginx不需要环境变量

⑤ 使用docker build对Dockerfile内容生成镜像

bash 复制代码
[root@docker-0001 nginx]# docker build -t myos:nginx .
...
Successfully built 9879ea2fc8f3
Successfully tagged myos:nginx

⑥ 基于myos:nginx镜像,启动容器并验证服务

bash 复制代码
[root@docker-0001 ~]# docker images
bash 复制代码
[root@docker-0001 ~]# docker run -itd myos:nginx    //运行容器,并放入后台
abfe8fcb0685ebccf3b3106813c8a019e9cc5609670a9457b3c59626762f868c
[root@docker-0001 ~]# docker ps -a
bash 复制代码
[root@docker-0001 ~]# docker inspect abfe8fcb0685
...
                   "IPAddress": "172.17.0.5",    //查看容器的IP
...
bash 复制代码
[root@docker-0001 ~]# curl http://172.17.0.5/info.html
bash 复制代码
[root@docker-0001 ~]# curl http://172.17.0.5/info.php

补充:Docker运行Nginx为什么要使用"nginx -g 'daemon off;"

  • 首先,Docker容器启动时,默认会把容器内部的第一个进程(上帝进程),也就是pid=1的程序作为docker容器是否正在运行的依据,如果docker 容器pid=1进程挂了,那么docker容器便会直接退出。
  • 其次,Nginx程序启动并在后台运行,这时Nginx并不是pid为1的程序,而是执行的bash,这个bash执行了Nginx指令后就挂了(Nginx运行会再开一个后台子进程,并将父进程杀掉)
  • 然后,当Docker run的时候把command作为容器内部启动命令,如果使用Nginx,那么Nginx程序将在后台运行,Docker未执行自定义的CMD之前,Nginx的pid是1,执行到CMD之后,Nginx就在后台运行,bash或sh脚本的pid变成了1。所以一旦执行完自定义CMD,Nginx容器也就退出了。
  • 所以,使用Docker编写Nginx镜像CMD容器启动命令时,需要使用"nginx -g 'daemon off;" 让Nginx在当前进程pid=1(前台)下执行主程序;

四、发布容器服务

访问容器服务遇到问题:

  • 默认容器可以访问外网,但外部网络的主机不可以访问容器内的资源,容器每次创建IP地址都会改变;

  • 解决这个问题的最佳方法是端口绑定,容器可以与宿主机的端口进行绑定,从而把宿主机变成对应的服务,不用关系容器的IP地址;

1、发布容器服务

在 Docker 中,使用 -p 参数可以将容器的端口与宿主机的端口进行绑定,从而使容器内的服务可以通过宿主机的网络进行访问。以下是详细的使用方法和注意事项。

  • 格式:docker run -itd -p 宿主机端口:容器端口 镜像名称:标签

-itd:-i 表示交互式运行,-t 表示分配一个伪终端,-d 表示在后台运行容器。

-p:用于端口映射,将宿主机的端口与容器的端口绑定。

宿主机端口:容器端口:宿主机的端口在前,容器的端口在后。

镜像名称:标签:指定要运行的 Docker 镜像及其标签。

例如:当访问宿主机的 http://localhost:80 时,实际访问的是容器内运行在 8080 端口的服务

bash 复制代码
docker run -itd -p 80:8080 my-web-service:v1.0

**1)绑定多个端口:**使用多个 -p 参数来绑定多个端口

例如:容器的 8080 端口被映射到宿主机的 80 端口,容器的 8443 端口被映射到宿主机的 443 端口。

bash 复制代码
docker run -itd -p 80:8080 -p 443:8443 my-web-service:v1.0

**2)绑定特定 IP 地址:**指定宿主机的特定 IP 地址进行端口绑定

例如:只有通过 192.168.1.100:80 才能访问容器内的服务。

bash 复制代码
docker run -itd -p 192.168.1.100:80:8080 my-web-service:v1.0

注意事项:

  • 端口冲突:同一宿主机的同一端口只能绑定一个容器服务。如果尝试绑定已经使用的端口,Docker 会报错。
  • 安全性:确保只暴露必要的端口,避免不必要的安全风险。
  • 网络配置:在生产环境中,建议使用 Docker 的网络配置(如 bridge、host、overlay 等)来管理容器的网络访问。

示例:使用容器的宿主机对外发布容器服务

步骤1:给docker-0001云主机绑定一个公网IP:124.71.115.1

步骤2:对外发布服务Apache服务、Nginx服务

① 把docker-0001主机绑定Apache容器的端口,并提供Apahce服务

bash 复制代码
[root@docker-0001 ~]# docker run -itd -p 80:80 myos:httpd
eb809138c6c52bc03e519c3807a2f9e1341e516fd88b7d2e8ac81f2a6086875e
[root@docker-0001 ~]# ss -nlptu | grep :80
tcp    LISTEN     0      1024   [::]:80                 [::]:*                   users:(("docker-proxy",pid=32100,fd=4))

浏览器测试访问服务http://127.71.115.1

浏览器测试访问服务http://127.71.115.1/info.php

② 把docker-0001主机绑定Nginx容器的端口,并提供Nginx服务

bash 复制代码
[root@docker-0001 ~]# docker stop $(docker ps -q)   //启动Nginx服务前,停止Apache
[root@docker-0001 ~]# docker run -itd -p 80:80 myos:nginx
b142115293b22545071404038df5876995fe7b7cbeb2ebce1900528ae6a13468
[root@docker-0001 ~]# ss -nlptu | grep :80
tcp    LISTEN     0      1024   [::]:80                 [::]:*                   users:(("docker-proxy",pid=32353,fd=4))

浏览器测试访问服务http://127.71.115.1

浏览器测试访问服务http://127.71.115.1/info.html


注意:浏览器测试访问服务http://127.71.115.1/info.php不能解析,其中包含三个问题:

① 因先前压缩的Nginx程序目录时,并未修改nginx配置文件的PHP动态解析配置,导致WEB页面无法解析PHP文件,且直接进入容器修改Nginx配置文件,需要重启Nginx服务及其麻烦;(容器共享卷)

② PHP文件要解析,需交给php-fpm后端服务解析,而php容器则作为后端解析程序,但php容器需要怎么获取Nginx的php文件?(容器共享卷)

③ Nginx容器与PHP容器之间的通信及发布端口需要得到解决;(容器网络通信)

2、主机卷映射(Host Volume Mapping)

Docker 容器的设计初衷是轻量级、可移植的,因此不适合在容器内保存重要数据。主要原因包括:

  • 数据易丢失:容器可以随时被删除或替换,导致数据丢失。

  • 数据管理困难:在多个容器中修改数据非常困难,尤其是在容器之间需要共享数据时。

为了解决上述问题,Docker 提供了主机卷映射功能。通过将宿主机的文件或目录映射到容器中,可以实现以下目标:

  • 数据持久化:数据保存在宿主机上,即使容器被删除,数据仍然存在。
  • 数据共享:多个容器可以共享同一个宿主机目录,实现数据同步和共享。

映射原则:

目标对象不存在: 如果容器内的目标对象(文件或目录)不存在,Docker 会自动创建。
目标对象存在: 如果容器内的目标对象已经存在,Docker 会直接覆盖掉。
多容器共享: 多个容器可以映射同一个宿主机对象,实现数据共享。
**类型匹配:**文件只能映射文件,目录只能映射目录。

在启动容器时,可以使用 -v 参数将宿主机的文件或目录映射到容器中

    • 格式:docker run -itd -v 宿主机对象:容器内对象 镜像名称:标签

-v:用于指定卷映射,将宿主机的文件或目录映射到容器中。

宿主机对象:容器内对象:宿主机的文件或目录在前,容器的文件或目录在后。

例如:将宿主机的 /data 目录映射到容器内的 /app/data 目录,容器内的 /app/data 目录将与宿主机的 /data 目录同步,任何在 /app/data 目录中的更改都会反映在宿主机的 /data 目录中,反之亦然

bash 复制代码
docker run -itd -v /data:/app/data my-app:v1.0

1)多个卷映射

将宿主机的 /data 目录映射到容器内的 /app/data 目录,宿主机的 /config 目录映射到容器内的 /app/config 目录。

bash 复制代码
docker run -itd -v /data:/app/data -v /config:/app/config my-app:v1.0

注意事项:

  • 权限问题:确保宿主机上的文件或目录对 Docker 容器有适当的读写权限。
  • 数据一致性:在多容器共享同一个宿主机目录时,注意数据一致性和并发访问问题。
  • 备份与恢复:定期备份宿主机上的数据,以防止数据丢失。

示例:在宿主机上修改Nginx配置文件,通过卷映射到容器内

① 创建目录,修改配置文件

bash 复制代码
[root@docker-0001 ~]# mkdir /var/webconf
[root@docker-0001 ~]# cp /usr/local/nginx/conf/nginx.conf /var/webconf/
[root@docker-0001 ~]# vim /var/webconf/nginx.conf
         location ~ \.php$ {
             root           html;
             fastcgi_pass   127.0.0.1:9000;
             fastcgi_index  index.php;
         #   fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
             include        fastcgi.conf;
         }

② 启用容器并映射宿主机的nginx.conf文件到容器内的nginx.conf文件

    • 格式:docker run -itd -p 宿主机端口:容器端口 镜像名称:标签
bash 复制代码
[root@docker-0001 ~]# docker run -itd -p 80:80 --name nginx \
> -v /var/webconf/nginx.conf:/usr/local/nginx/conf/nginx.conf myos:nginx
a685e6096357597a4bfdc1bd7dca3dd7f60d21e760559966a8ce1e5ef534a636

③ 查看配置文件中,php动态解析相关配置是否被映射到容器内

bash 复制代码
[root@a685e6096357 ~]# cat /usr/local/nginx/conf/nginx.conf

3、容器网络通信

在 Docker 中,Nginx 容器调用 PHP-FPM 容器通常需要利用容器的网络特性,特别是通过共享网络命名空间来实现通信。以下是实现这一目标的步骤和方法。

① 共享网络命名空间

为了让 PHP-FPM 容器监听 Nginx 容器的网络端口,可以使用 Docker 的 container 网络模式,共享 Nginx 容器的网络命名空间。

docker run -itd --name nginx-container nginx:latest
docker run -itd --network container:nginx-container --name php-fpm-container php:fpm

在这个例子中,php-fpm-container 容器将与 nginx-container 容器共享网络命名空间,因此可以直接通过 localhost 或 127.0.0.1 进行通信。


② 共享卷映射

当客户端访问 Nginx 的 PHP 文件时,Nginx 会向后端 PHP-FPM 传递文件路径。由于 PHP-FPM 容器本身没有 Nginx 的文件,因此可以使用宿主机的共享卷,在 Nginx 和 PHP-FPM 容器之间共享目录。

docker run -itd -v /host/path/to/web:/usr/share/nginx/html --name nginx-container nginx:latest
docker run -itd -v /host/path/to/web:/usr/share/nginx/html --network container:nginx-container --name php-fpm-container php:fpm

在这个例子中,宿主机的 /host/path/to/web 目录被映射到 Nginx 和 PHP-FPM 容器的 /usr/share/nginx/html 目录。这样,PHP-FPM 容器可以找到并解析 PHP 文件,然后将解析结果反馈给 Nginx,最终返回给客户端。

1)Docker 网络通信模式

Docker 提供了多种网络通信模式,每种模式都有其特定的用途和适用场景。

    • 格式:docker run -itd --network container:共享容器 镜像名称:标签

① host 模式:容器与宿主机共享网络栈,容器的网络配置与宿主机完全相同

docker run -itd --network host 镜像名称:标签

**② container 模式:**新创建的容器与指定的容器共享网络命名空间

docker run -itd --network container:共享容器 镜像名称:标签

**③ none 模式:**容器没有网络配置,不与任何网络连接

docker run -itd --network none 镜像名称:标签

**④ bridge 模式:**Docker 的默认网络模式,容器通过 Docker 的虚拟网桥进行通信

docker run -itd 镜像名称:标签

**⑤ 自定义网络:**允许用户创建自定义的桥接网络或 overlay 网络,以满足特定的网络需求

docker network create my-custom-network
docker run -itd --network my-custom-network 镜像名称:标签

示例:结合容器共享卷+容器网络通信,将Nginx服务上线

提前将所需网页文件拷贝到192.168.1.31中(参考:kubernetes/docker-images)

bash 复制代码
[root@ecs-proxy docker-images]# scp info.php info.html 192.168.1.31:/root

步骤1:创建目录,并将所需网页文件、配置文件拷贝到对应目录

bash 复制代码
[root@docker-0001 ~]# mkdir -p /var/{webroot,webconf}
[root@docker-0001 ~]# cp info.php info.html /var/webroot/    //共享网页目录
[root@docker-0001 ~]# cp /usr/local/nginx/conf/nginx.conf /var/webconf/
[root@docker-0001 ~]# vim /var/webconf/nginx.conf    //修改配置文件
        location ~ \.php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
        #   fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
            include        fastcgi.conf;
        }

步骤2:停止并删除所有的容器

bash 复制代码
[root@docker-0001 ~]# docker stop $(docker ps -qa)
[root@docker-0001 ~]# docker rm $(docker ps -qa)

步骤3:启动前端nginx服务,并映射共享目录和配置文件

bash 复制代码
[root@docker-0001 ~]# docker images
bash 复制代码
[root@docker-0001 ~]# docker run -itd --name nginx -p 80:80 \
> -v /var/webconf/nginx.conf:/usr/local/nginx/conf/nginx.conf \
> -v /var/webroot/:/usr/local/nginx/html/ myos:nginx
f3f2f92d2df2b4381e19d5703a7b78d485e1429180356e27dd8cc717a9a2b047

步骤4:启动后端 php 服务,并映射共享目录

bash 复制代码
[root@docker-0001 ~]# docker run -itd --network=container:nginx \
> -v /var/webroot/:/usr/local/nginx/html/ myos:php-fpm
155d8c8625a8bc1b611da7298b6d2a158359f54de9b0410b396e81af63cb500b

解释:network=container:nginx,共享nginx容器的网络命名空间,两个容器共用网卡,是nginx容器的eth0地址,所以不需要再用【-p】发布端口;启动php容器后能监听到80和9000端口,但监听的80端口无法控制也无法查到对应服务,该80端口由nginx容器进行控制;

步骤5:验证服务

bash 复制代码
[root@docker-0001 ~]# curl http://docker-0001/info.html
<html>
  <marquee  behavior="alternate">
      <font size="12px" color=#00ff00>Hello World</font>
  </marquee>
</html>

[root@docker-0001 ~]# curl http://docker-0001/info.php
<pre>
Array
(
    [REMOTE_ADDR] => 172.17.0.1
    [REQUEST_METHOD] => GET
    [HTTP_USER_AGENT] => curl/7.29.0
    [REQUEST_URI] => /info.php
)
php_host:       f3f2f92d2df2
1229

五、Docker私有镜像仓库

1、私有仓库的用途

私有仓库是组建容器集群的必要组件,主要用途包括:

  • 镜像管理:集中管理内部使用的 Docker 镜像,确保镜像的安全性和一致性。
  • 版本控制:方便进行镜像的版本控制和回滚。
  • 加速部署:减少从公共仓库拉取镜像的时间,加速容器部署。

2、搭建私有仓库(服务端)

① 安装私有仓库软件

使用 yum 安装 docker-distribution 软件包:

yum install docker-distribution

② 启动私有仓库,并设置开机自启动

systemctl enable --now docker-distribution
  • 仓库配置文件 :/etc/docker-distribution/registry/config.yml
  • 数据存储路径 :/var/lib/registry/
  • 默认端口号:5000

查看私有镜像仓库中的镜像名称或标签

注意:私有仓库里的镜像与 Docker 本地镜像不是同一个对象。私有仓库的镜像必须使用curl 命令查询,而本地镜像可以通过 docker images 查看。

3、管理私有仓库(客户端)

为了让本地 Docker 客户端知道私有仓库的地址,需要编辑 /etc/docker/daemon.json 文件,添加以下内容:

{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "registry-mirrors": ["https://hub-mirror.c.163.com"],
  "insecure-registries": ["192.168.1.100:5000", "registry:5000"]
}

cgroup 驱动:Docker 默认驱动是 cgroupfs,可以改为 systemd 以提高性能。

默认下载仓库:使用国内镜像源加速访问。

私有仓库地址:指定私有镜像仓库的 IP 地址和端口号。

编辑完成后,重启 Docker 服务:

systemctl restart docker

4、为镜像创建标签,上传镜像:

1)创建标签

为本地镜像创建标签,指向私有仓库:docker tag 本地镜像:标签 私有镜像仓库IP:5000/镜像:标签

例如:

bash 复制代码
docker tag my-image:latest 192.168.1.100:5000/my-image:latest

2)上传镜像

将镜像推送到私有仓库:docker push 私有镜像仓库IP:5000/镜像:标签

例如:

bash 复制代码
docker push 192.168.1.100:5000/my-image:latest

注意:镜像名称必须包含私有仓库的 IP 地址和路径,否则无法确定上传位置

5、通过私有仓库镜像启动容器

使用私有仓库中的镜像启动容器:docker run -it 私有镜像仓库IP:5000/镜像:标签

例如:

bash 复制代码
docker run -it 192.168.1.100:5000/my-image:latest

**总结:**通过搭建和管理私有镜像仓库,可以有效管理内部使用的 Docker 镜像,确保镜像的安全性和一致性。合理配置私有仓库和客户端,可以加速容器部署和版本控制。


示例:部署Docker私有仓库

|----------|---------------|-----------|
| 主机名 | IP地址 | 最低配置 |
| registry | 192.168.1.100 | 1CPU,1G内存 |

步骤1:购买1台云主机

bash 复制代码
[root@ecs-proxy ~]# ping 192.168.1.100
PING 192.168.1.100 (192.168.1.100) 56(84) bytes of data.
64 bytes from 192.168.1.100: icmp_seq=15 ttl=64 time=0.748 ms
64 bytes from 192.168.1.100: icmp_seq=16 ttl=64 time=0.219 ms

步骤2:搭建私有仓库(registry操作)

bash 复制代码
[root@ecs-proxy ~]# ssh 192.168.1.100
[root@registry ~]# yum -y install docker-distribution    //安装软件包
[root@registry ~]# systemctl enable --now docker-distribution  //开启服务并设开机自启
[root@registry ~]# curl http://192.168.1.100:5000/v2/_catalog  //查看私有仓库中的镜像名称
{"repositories":[]}

步骤3:Docker客户端配置(docker-0001操作)

bash 复制代码
[root@docker-0001 ~]# vim /etc/docker/daemon.json
{
    "exec-opts": ["native.cgroupdriver=systemd"],   //cgroup驱动
    "registry-mirrors": ["https://hub-mirror.c.163.com"],   // 默认下载仓库
    "insecure-registries":["192.168.1.100:5000", "registry:5000"]   //私有仓库地址
}
[root@docker-0001 ~]# systemctl restart docker.service   //重启服务
[root@docker-0001 ~]# docker info | grep Cgroup   //查看容器信息
Cgroup Driver: systemd

步骤4:上传镜像(myos:latest, myos:httpd, myos:nginx, myos:php-fpm)

  • 格式:docker tag 本地镜像:标签 私有镜像仓库IP:5000/镜像:标签 //创建标签
  • 格式:docker push 私有镜像仓库IP:5000/镜像:标签 //上传镜像
bash 复制代码
[root@docker-0001 ~]# docker tag myos:latest 192.168.1.100:5000/myos:latest
[root@docker-0001 ~]# docker images
bash 复制代码
[root@docker-0001 ~]# docker push 192.168.1.100:5000/myos:latest
The push refers to repository [192.168.1.100:5000/myos]
f22c5cb6be20: Pushed
bcc97fbfc9e1: Pushed
latest: digest: sha256:4a8d25a7efe3c962c8ec7eb2b21d6d3817319d3e738a4b8fd8d45f4dc9f8cb9a size: 741

使用For循环批量上传镜像

bash 复制代码
[root@docker-0001 ~]# for i in httpd php-fpm nginx
> do
> docker tag myos:${i} 192.168.1.100:5000/myos:${i}
> docker push 192.168.1.100:5000/myos:${i}
> done

步骤5:验证测试,查看私有镜像仓库中的镜像名称和标签(docker-0002操作)

bash 复制代码
[root@docker-0001 ~]# ssh 192.168.1.32
[root@docker-0002 ~]# curl http://192.168.1.100:5000/v2/_catalog
{"repositories":["myos"]}
[root@docker-0002 ~]# curl http://192.168.1.100:5000/v2/myos/tags/list
{"name":"myos","tags":["php-fpm","httpd","latest","nginx"]}

步骤6:验证测试,使用远程镜像启动容器(docker-0002操作)

  • 格式:docker run -it 私有镜像仓库IP:5000/镜像:标签

① Docker端编写配置文件,连接私有仓库

bash 复制代码
[root@docker-0002 ~]# vim /etc/docker/daemon.json
{
    "exec-opts": ["native.cgroupdriver=systemd"],
    "registry-mirrors": ["https://hub-mirror.c.163.com"],
    "insecure-registries":["192.168.1.100:5000", "registry:5000"]
}
[root@docker-0002 ~]# systemctl restart docker   //重启服务

② 使用远程镜像启动容器

bash 复制代码
[root@docker-0002 ~]# docker run -it 192.168.1.100:5000/myos:latest
Unable to find image '192.168.1.100:5000/myos:latest' locally
latest: Pulling from myos
7dc0dca2b151: Pull complete
62f184ddaa87: Pull complete
Digest: sha256:4a8d25a7efe3c962c8ec7eb2b21d6d3817319d3e738a4b8fd8d45f4dc9f8cb9a
[root@238c1ad313d4 /]# exit
Exit
bash 复制代码
[root@docker-0002 ~]# docker ps -a
bash 复制代码
[root@docker-0002 ~]# docker images

步骤6:下载镜像

bash 复制代码
[root@docker-0002 ~]# docker pull 192.168.1.100:5000/myos:httpd
httpd: Pulling from myos
7dc0dca2b151: Already exists
62f184ddaa87: Already exists
7def584b8ca0: Pull complete
2be9ee4dc167: Pull complete
Digest: sha256:23c1514167627cad7ab9bf90bab5852a2908a0a1e902bf251da125c68c71cb91
Status: Downloaded newer image for 192.168.1.100:5000/myos:httpd
[root@docker-0002 ~]# docker run -itd 192.168.1.100:5000/myos:httpd
b2209bfc1188312a2e8a055ce1059f3927101c2fb8230eb49e3138d7bbac6928

**常见报错:**Docker本地端未编写配置文件指定私有仓库地址,则会有以下报错

扩展知识:使用Dockerfile制作Tomcat的镜像

步骤1:自定义基础镜像

① 拷贝镜像压缩包到192.168.1.32

bash 复制代码
[root@ecs-proxy ~]# scp /root/kubernetes/docker-images/centos.tar.gz 192.168.1.32:/root/

② 导入镜像压缩包

bash 复制代码
[root@node-0002 ~]# docker load -i centos.tar.gz

③ 修改镜像内容

bash 复制代码
[root@node-0002 ~]# docker run -it centos:latest /bin/bash
[root@76e6c1740ccc /]# rm -rf /etc/yum.repos.d/*.repo
[root@76e6c1740ccc /]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.myhuaweicloud.com/repo/CentOS-Base-7.repo
[root@76e6c1740ccc /]# yum install -y net-tools vim-enhanced tree bash-completion iproute psmisc && yum clean all
[root@76e6c1740ccc /]# exit

④ 创建自定义镜像

bash 复制代码
[root@node-0002 ~]# docker ps -a
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS                         PORTS               NAMES
76e6c1740ccc        centos:latest                   "/bin/bash"              2 minutes ago       Exited (0) 30 seconds ago                          hopeful_noether
[root@node-0002 ~]# docker commit 76e6c1740ccc baseos:latest
sha256:1ca4ec4086ba5b50d2b6e95e298f96a37e3163b086f639d2ff3d2f4ede75f572
[root@node-0002 ~]# docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
baseos                          latest              1ca4ec4086ba        12 seconds ago      281MB

步骤2:通过Dockerfil制作Tomcat镜像

① 创建存放目录

bash 复制代码
[root@node-0002 ~]# mkdir tomcat ; cd tomcat
[root@node-0002 tomcat]# exit
logout
[root@ecs-proxy ~]# scp apache-tomcat-9.0.6.tar.gz 192.168.1.32:/root/tomcat
[root@node-0002 tomcat]# ls
apache-tomcat-9.0.6.tar.gz

② 编写Dockerfile文件

bash 复制代码
[root@node-0002 tomcat]# vim Dockerfile
FROM baseos:latest
RUN yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel && useradd tomcat
ADD apache-tomcat-9.0.6.tar.gz /usr/local/
EXPOSE 8080
CMD ["/usr/local/apache-tomcat-9.0.6/bin/catalina.sh","run"]

③ 使用docker build对Dockerfile内容生成镜像

bash 复制代码
[root@node-0002 tomcat]# docker build -t myos:tomcat .
...
Successfully built f73ed852de80
Successfully tagged myos:tomcat
[root@node-0002 tomcat]# docker run -itd myos:tomcat
a4c84ef277549a39bb19f811e219e950d587edc33c125e41eb9c570f20d93090
[root@node-0002 tomcat]# docker exec -it a4c84ef277 /bin/bash
[root@a4c84ef27754 /]# ss -nlptu | grep :8080
tcp    LISTEN     0      100       *:8080                  *:*                   users:(("java",pid=1,fd=51))

思维导图:

小结:

本篇章节为**【第五阶段】CLOUD-DAY5** 的学习笔记,这篇笔记可以初步了解到 容器的镜像编排,commit简单镜像创建,Dockerfile制作服务镜像(语法、创建镜像)、创建复杂镜像(Docker微服务架构、示例:NGINX+PHP)、私有仓库。


Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解。

相关推荐
编程修仙15 分钟前
Collections工具类
linux·windows·python
芝麻团坚果31 分钟前
对subprocess启动的子进程使用VSCode python debugger
linux·ide·python·subprocess·vscode debugger
Elastic 中国社区官方博客36 分钟前
Elasticsearch 中的热点以及如何使用 AutoOps 解决它们
大数据·运维·elasticsearch·搜索引擎·全文检索
写点什么啦37 分钟前
[debug]不同的window连接ubuntu的vscode后无法正常加载kernel
linux·vscode·ubuntu·debug
wellnw44 分钟前
[ubuntu]编译共享内存读取出现read.c:(.text+0x1a): undefined reference to `shm_open‘问题解决方案
linux·ubuntu
不爱学习的YY酱1 小时前
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
java·linux·前端·算法·操作系统
DC_BLOG1 小时前
Linux-Nginx虚拟主机
linux·运维·nginx
坐公交也用券1 小时前
使用Python3实现Gitee码云自动化发布
运维·gitee·自动化
一名路过的小码农1 小时前
ceph 18.2.4二次开发,docker镜像制作
ceph·docker·容器
XY.散人1 小时前
初识Linux · 信号处理 · 续
linux·信号处理