Docker
浪费了很多时间在重新配置环境上面,我不中了
原理:
理解成一个平台中搭建不同容器,执行不同进程,需要不同进程相互不可见,完全独立出去,就需要将进程隔离出去。
在Linux系统中,对一个进程进行隔离,主要是通过Namespace和Cgroup两大机制实现的。
Namespace(命名空间)机制是Linux内核提供的一种资源隔离技术,它将全局系统资源(如进程ID、网络、挂载点)划分成多个独立的空间,使不同进程组感觉拥有独立的操作系统视图。
- Mount (挂载) (CLONE_NEWNS): 隔离文件系统挂载点,使进程拥有独立的挂载视图。
- UTS (Unix Timesharing System) (CLONE_NEWUTS): 隔离主机名和域名。
- IPC (Interprocess Communication) (CLONE_NEWIPC): 隔离进程间通信资源(如消息队列、信号量)。
- PID (Process ID) (CLONE_NEWPID): 隔离进程ID,不同命名空间可有相同的PID(例如每个容器内都有1号进程)。
- Network (网络) (CLONE_NEWNET): 隔离网络设备、IP地址、端口和路由表。
- User (用户) (CLONE_NEWUSER): 隔离用户和组ID,可实现容器内root用户映射为宿主机上的非特权用户。
Cgroup (Control Groups) 是 Linux 内核的一项功能,用于对进程组进行物理资源(CPU、内存、磁盘 I/O、网络)的限制、控制和隔离。
在 Linux 中,# 符号就代表当前是 root 用户,而 $ 才代表普通用户
一个容器进程本质上是一个运行在沙盒中的隔离进程,由Linux系统本身负责隔离,Docker只是提供了一系列工具,帮助我们设置好隔离环境后,启动这个进程。
最基本的隔离就是进程之间看不到彼此,这是由Linux的Namespace机制实现的。进程隔离的结果就是以隔离方式启动的进程看到的自身进程ID总是1,且看不到系统的其他进程。
第二种隔离就是隔离系统真实的文件系统。Docker利用Linux的mount机制,给每个隔离进程挂载了一个虚拟的文件系统,使得一个隔离进程只能访问这个虚拟的文件系统,无法看到系统真实的文件系统。相当于就是一个去获取一个真实文件(实际文件被隔离出去),投射到一个虚拟文件系统里。再把投射的这个虚拟文件和需要用到的第三方库或者需要使其中程序正常进行,其他的配置系统一起打包成为一个Dockerfile,再把Dockerfile和Docker运行的依赖打包就成为Docker镜像。启动进程的时候就相当于逐层解压,最后成为一个虚拟的文件系统。
第三种隔离就是网络协议栈的隔离
Redis(Remote Dictionary Server)是一个开源的内存数据库,遵守 BSD 协议,它提供了一个高性能的键值(key-value)存储系统,常用于缓存、消息队列、会话存储等应用场景。
在Docker中运行一个Redis,用宿主机去连接Redis,这里Redis的监听相当于也是发生在Docker内部。由于Linux的网络隔离,Redis进程拥有与宿主机不同的网络空间,所以需要把Redis进程的端口号映射到宿主机
如果同时运行相当于两个进程的话,通过将不同进程服务名称也解析为动态分配的IP地址,相当于是同一IP下的不同端口的分配的不同活动
表面上看上去一致的内容,类似于不同进程看本身的ID都是1,表现的就是无法直接从IP地址上去区别实际内容。
Docker Compose 是一个用于定义和运行多容器 Docker 应用的官方工具。它使用 YAML 文件(docker-compose.yml)配置多个容器服务、网络和数据卷,通过 docker-compose up 一键启动、停止和管理整个应用堆栈,特别适用于开发、测试和单机生产环境的复杂应用编排。
解决镜像拉取问题的方案:
配置镜像加速器
这是最标准、最持久有效的方案。通过修改Docker守护进程的配置文件,为所有镜像拉取请求指定一个高速缓存代理 。
但是我在搭这个环境的时候,不知道什么原因,配置加速器反而拉取失败了,感觉可能是连接问题,好吧我在配代理的时候也遇到了这个问题,现在串起来了好家伙
编辑(或创建)Docker的配置文件 sudo vi /etc/docker/daemon.json。
输入以下内容(可配置多个加速地址以实现负载均衡):
1 | { |
重启Docker服务使配置生效:sudo systemctl daemon-reload && sudo systemctl restart docker。
验证配置:docker info | grep "Registry Mirrors" -A 1,看到配置的地址列表即表示成功 。
让科学上网方法生效
科学上网工具可以让Docker守护进程的请求通过代理发送。为Docker服务设置HTTP/HTTPS代理。
操作步骤:
为Docker服务创建独立的配置目录:
sudo mkdir -p /etc/systemd/system/docker.service.d创建配置文件:
sudo vi /etc/systemd/system/docker.service.d/http-proxy.conf填入代理地址(假设宿主机代理端口是
1080,且Docker守护进程有权限访问):1
2
3
4[Service]
Environment="HTTP_PROXY=http://宿主机IP:1080"
Environment="HTTPS_PROXY=http://宿主机IP:1080"
Environment="NO_PROXY=localhost,127.0.0.1,.local"重新加载配置并重启:
sudo systemctl daemon-reload && sudo systemctl restart docker。
Dockerfile
Dockerfile举例
1 | FROM php:7.4-apache |
其中
FROM php:7.4-apache指定基础镜像,这个镜像Apache 已安装并配置好,PHP 已与 Apache 集成,默认网站目录:/var/www/html一步到位。COPY src/ /var/www/html/把本地源码拷贝进容器。宿主机当前目录下的src文件夹内容,复制到容器的/var/www/html/(网页根目录)- 这样访问
http://ip:port/index.php就可以执行源码。如果有多个文件,都可以访问http://ip:port/phpinfo.php COPY flag /flag把宿主机当前目录下的flag文件,复制到容器根目录/flagRUN chmod 444 /flag设置 flag 文件权限为“只读”444 = r-- r-- r--也可以设置为400只允许root读,这样就不得不提权了。RUN a2enmod rewrite启用 Apache 的 rewrite 重写模块,实现伪静态 URL,路由转发,访问控制。(这个不是每道题都要用,但还是写上)ENV FLAG=flag{Th1s_is_a_fake_flag}添加环境变量。EXPOSE 80声明容器对外暴露 80 端口WORKDIR /var/www/html设置工作目录CMD ["apache2-foreground"]默认启动apache
docker的相关命令:
| 命令 | 作用 |
|---|---|
docker pull <镜像名>:<标签> |
从仓库拉取镜像,如 docker pull ubuntu:22.04 |
docker images |
列出本地所有镜像 |
docker rmi <镜像ID或名称> |
删除本地一个或多个镜像 |
docker build -t <镜像名>:<标签> . |
根据当前目录下的 Dockerfile 构建镜像 |
docker tag <源镜像> <目标镜像:标签> |
给镜像打标签,常用于推送前重命名 |
docker push <镜像名>:<标签> |
将镜像推送到远程仓库(需先登录) |
docker search <关键词> |
在 Docker Hub 上搜索镜像 |
docker run [选项] <镜像> [命令] |
创建并启动一个新容器(最常用,选项如 -d 后台、-it 交互、--name 命名、-p 端口映射、-v 挂载) |
docker ps |
列出正在运行的容器(加 -a 列出所有容器,包括已停止的) |
docker stop <容器ID或名称> |
停止一个运行中的容器 |
docker start <容器ID或名称> |
启动一个已停止的容器 |
docker restart <容器ID或名称> |
重启容器 |
docker rm <容器ID或名称> |
删除一个或多个已停止的容器(加 -f 强制删除运行中的) |
docker logs <容器ID或名称> |
查看容器的日志输出(加 -f 持续跟踪) |
docker exec -it <容器ID或名称> <命令> |
在运行中的容器内执行命令(例如 docker exec -it mycontainer bash 进入容器终端) |
docker inspect <容器ID或名称> |
查看容器的详细信息(JSON 格式) |
docker version |
显示 Docker 客户端和服务端版本信息 |
docker info |
显示 Docker 系统信息(容器数、镜像数、存储驱动等) |
docker system df |
查看镜像、容器、卷所占用的磁盘空间 |
docker system prune |
清理不再使用的资源(容器、网络、镜像、构建缓存),加 -a 清理更彻底 |
docker network ls |
列出所有网络 |
docker network create <网络名> |
创建一个新的桥接网络 |
docker network connect <网络名> <容器> |
将容器连接到指定网络 |
docker network disconnect <网络名> <容器> |
将容器从网络断开 |
docker network inspect <网络名> |
查看网络的详细信息 |
docker volume ls |
列出所有卷 |
docker volume create <卷名> |
创建一个数据卷 |
docker volume inspect <卷名> |
查看卷的详细信息 |
docker volume rm <卷名> |
删除一个卷 |
docker volume prune |
删除所有未使用的卷 |
docker cp <源路径> <容器:目标路径> |
在宿主机和容器之间复制文件/目录 |
docker commit <容器> <镜像名:标签> |
将容器的当前状态保存为新镜像 |
docker export <容器> -o 文件名.tar |
将容器的文件系统导出为 tar 包 |
docker import 文件名.tar <镜像名:标签> |
从 tar 包导入镜像 |
docker save <镜像> -o 文件名.tar |
将一个或多个镜像保存为 tar 包 |
docker load -i 文件名.tar |
从 tar 包加载镜像 |
docker login |
登录 Docker Hub 或其他私有仓库 |
docker logout |
登出仓库 |
比如docker run -d,运行容器,如果没有对应容器就会创建之后再运行
可以用docker exec -it pear_test bash可以在控制台进入容器,方便调试。
创建成功之后,返回的字符就是容器id
拿之前挂载靶场文件使用的命令举例
docker run
Docker 的核心命令,用于基于指定镜像创建并运行一个新容器。-d
后台运行容器(detach 模式),容器启动后不会占用当前终端,而是在后台运行。--name lfi-lab
为容器指定一个名称lfi-lab,方便后续通过该名称管理容器(如停止、查看日志等),若不指定则 Docker 会随机生成一个名称。-p 8082:80
端口映射,将宿主机的8082端口映射到容器的80端口。这样访问宿主机http://localhost:8082即可访问容器内运行的 Web 服务(容器内 Apache 默认监听 80 端口)。-v "D:\phpstudy_pro\WWW\lfi-labs-master:/var/www/html"
卷挂载(volume mount),将宿主机上的目录D:\phpstudy_pro\WWW\lfi-labs-master挂载到容器内的/var/www/html目录。/var/www/html是 Apache 的默认 Web 根目录。- 这样做可以将本地的 PHP 项目代码直接同步到容器中,方便开发调试或运行特定应用(如 LFI 测试靶场),且代码在宿主机上修改后会实时反映在容器内。
php:7.3-apache
指定使用的 Docker 镜像,这里是一个预装了 PHP 7.3 和 Apache 的官方镜像。容器将以此镜像为基础运行。
复制文件时关于忽略部分文件的方式:
解决方案是使用 .dockerignore 文件,它的工作原理类似于.gitignore 。
.gitignore 文件用于定义 Git 项目中无需追踪和提交的文件或目录(如日志、编译产物、IDE 配置)。在仓库根目录创建该文件,按行写入匹配模式(支持通配符),即可实现忽略。已提交的文件需用 git rm –cached 移除追踪。
- 在执行
docker build命令的目录下(也就是构建上下文的根目录),创建一个名为.dockerignore的文件。
1 | # .dockerignore 示例(注释用 # 开头) |
当执行 COPY . /app 时,Docker 会先读取 .dockerignore 中的规则,自动过滤掉这些文件,只复制不没有包含在这些文件中的内容。
Docker-compose.yml或Docker-compose.yaml文件
Dockerfile只可以用来构建单个镜像,在docker-compose.yml文件中,可以定义多个服务,每个服务可以包含一系列配置选项,例如镜像名称、容器端口、环境变量等。
1 | # 指定 compose 文件版本(推荐用 3.x,兼容性最好) |
一个依赖Redis数据库的web应用
1 | version: '3.8' |
- web 服务:基于当前目录下的
Dockerfile构建一个 Web 应用镜像,并将容器内的 8000 端口映射到宿主机的 8000 端口。通过环境变量REDIS_HOST=redis告诉 Web 应用如何连接到 Redis(服务名redis在 Docker Compose 内部网络中会自动解析为对应容器的 IP)。它还设置了容器启动顺序依赖(depends_on),确保 Redis 服务先启动。另外通过卷挂载将当前代码目录挂载到容器的/app,便于开发时实时更新代码。 - redis 服务:使用官方的
redis:alpine镜像,没有向宿主机暴露端口,仅供内部网络中的 Web 服务访问。
