在现代应用开发中,Docker 是一种非常流行的技术,用于打包、分发和运行应用程序。这篇博文将介绍如何使用 Docker 创建一个 HTTP 服务端,打包成 Docker 镜像,并在本地进行测试,包括如何模拟客户端发送 POST 请求。
1. 介绍
本篇博客的目标是:
-
创建一个简单的 HTTP 服务端应用。
-
将应用打包成 Docker 镜像。
-
启动并测试 HTTP 服务端。
-
使用
curl
模拟客户端向服务端发送 POST 请求。 -
管理 Docker 容器和镜像,包括停止、删除容器和镜像。
2. 创建 HTTP 服务端
如果你用的是C++11,那么就可以用httplib库来完成window和linux下的HTTP相关操作。在这个库中,作者已给出服务器端和客户端的示例代码,可以直接运行。路径是"cpp-httplib-master\example\example.sln"
相当于已经有一个现成的 HTTP 服务端应用,只需要往里面添加请求。此处我假设服务端处理 POST
请求,通过指定路径 /get_route
来接收 JSON 数据,并返回一个 JSON 响应。
json库指路:GitHub - nlohmann/json: JSON for Modern C++
示例代码(C++ HTTP 服务端)
cpp
#include <httplib.h>
#include <nlohmann/json.hpp>
int main() {
httplib::Server svr;
svr.Post("/get_route", [&](const httplib::Request& req, httplib::Response& res) {
try {
// 解析请求体中的 JSON 数据
nlohmann::json request_data = nlohmann::json::parse(req.body);
// 进行逻辑处理(例如,执行某种数据处理算法)
// 假设我们有一个处理函数 `process_route`,会根据请求的内容计算路径
nlohmann::json response_data = process_route(request_data);
// 返回 JSON 响应
res.set_content(response_data.dump(), "application/json");
} catch (const std::exception& e) {
res.status = 400;
res.set_content("{\"error\": \"Invalid JSON data\"}", "application/json");
}
});
// 启动服务端,监听 8080 端口
svr.listen("0.0.0.0", 8080);
return 0;
}
3. 打包 Docker 镜像
在linux环境下通过 Docker 将客户端打包成镜像,方便在任何支持 Docker 的环境中运行。以下是将应用打包为 Docker 镜像的步骤。
3.1. 创建 Dockerfile
首先,我们需要一个 Dockerfile
来描述如何构建镜像。 Dockerfile
文件需要在当前工程目录下
下面是一个我的 Dockerfile 示例:
cpp
# 使用官方 Ubuntu 20.04 镜像作为基础镜像
FROM ubuntu:20.04
# 设置时区
ENV TZ=Asia/Shanghai
RUN apt-get update && apt-get install -y \
tzdata \
&& dpkg-reconfigure --frontend noninteractive tzdata
# 安装必要的系统依赖(根据项目需要添加)
RUN apt-get install -y \
build-essential \
libboost-all-dev \
libstdc++6 \
libssl-dev \
libcurl4-openssl-dev \
wget \
curl \
ca-certificates \
&& apt-get clean
# 创建工作目录
WORKDIR /app
# 复制 .dockerignore 文件中未忽略的项目文件(可以通过 .dockerignore 排除不需要的文件)
COPY . .
# 复制编译后的可执行文件到容器中的 /usr/local/bin 路径
COPY ./bin/AvoidObs_Search /usr/local/bin/AvoidObs_Search
# 设置容器内的默认命令
ENTRYPOINT ["/usr/local/bin/AvoidObs_Search"]
# 可选:如果需要将配置文件挂载到容器中,可以在运行容器时使用 -v 选项来挂载
# EXPOSE 8080
# 默认的运行参数可以根据实际需求修改
CMD ["--help"]
3.2. 构建 Docker 镜像
使用 docker build
命令来构建镜像。该命令要求在项目的根目录下,输入pwd
查看当前路径,并且确认包含 Dockerfile
。
bash
docker build -t avoidobs-search:1.0 .
此命令会根据 Dockerfile
的定义,打包出一个名为 avoidobs-search:1.0
的镜像。
3.3. 运行 Docker 容器
一旦镜像构建完成,就可以使用以下命令来启动容器:
bash
docker run -it -p 8080:8080 avoidobs-search:1.0
这个命令将容器的 8080 端口映射到主机的 8080 端口,允许从外部访问服务。
4. 测试 HTTP 服务
在 Docker 容器启动后,服务已经在 8080 端口监听请求。接下来,我们使用 curl
来模拟客户端发送一个 POST 请求。
4.1. 使用 curl
发送 POST 请求
curl
是一个强大的命令行工具,用于向 URL 发送请求。在本例中,我们发送一个包含多个字段的 JSON 数据:
bash
curl -X POST http://localhost:8080/get_route -H "Content-Type: application/json" -d "{\"num_uavs\": 5, \"flag_use_avoid_obs\": 1, \"grid_size\": 250, \"rally_point\": {\"lat\": 300986462, \"lng\": 1079954736}, \"strike_point\": {\"lat\": 300727124, \"lng\": 1085859475}, \"avoidance_area\": [{ \"lat\": 323933074, \"lng\": 1047571967 }, { \"lat\": 324415592, \"lng\": 1083385845 }, { \"lat\": 297743777, \"lng\": 1083237961 }, { \"lat\": 297827300, \"lng\": 1046171234 }], \"search_area\": [{ \"lat\": 301008931, \"lng\": 1081017137 }, { \"lat\": 303906132, \"lng\": 1083715730 }, { \"lat\": 303176929, \"lng\": 1089347623 }, { \"lat\": 298410734, \"lng\": 1086922078 }, { \"lat\": 299130795, \"lng\": 1081810098 }], \"obstacles\": [{ \"obs_type\": 1, \"circle\": { \"radius\": 2000000, \"lat\": 314529743, \"lng\": 1061959970 } }, { \"obs_type\": 1, \"circle\": { \"radius\": 2000000, \"lat\": 305723418, \"lng\": 1059969981 } }, { \"obs_type\": 0, \"polygon\": [{ \"lat\": 318753658, \"lng\": 1073292651 }, { \"lat\": 318312837, \"lng\": 1075420574 }, { \"lat\": 317308720, \"lng\": 1074607380 }] }]}"
4.2. 解释 curl
命令:
-
-X POST
:指定 HTTP 请求方法为 POST。 -
-H "Content-Type: application/json"
:指定请求头,告诉服务端请求体是 JSON 格式。 -
-d
:指定请求体数据,传递给服务端的 JSON 数据。
5. Docker 容器与镜像管理
在整个过程中,不停调整代码逻辑,因此要管理 Docker 容器和镜像。以下是一些常用命令:
5.1. 查看 Docker 容器
bash
docker ps -a
5.2. 停止 Docker 容器
这里要用的是容器ID,即docker ps -a得到的
bash
docker stop <CONTAINER ID>
5.3. 删除 Docker 容器
这里要用的是容器ID,即docker ps -a得到的
bash
docker rm <CONTAINER ID>
5.4. 查看 Docker 镜像信息
bash
docker images
5.5. 删除 Docker 镜像
这里要用的是镜像ID,即docker images得到的
bash
docker rmi <IMAGE ID>
6. 遇到的问题
6.1. 读取文件
关于可执行程序需要读取文件和输出文件的问题
从Docker打包的镜像中运行AvoidObs_Search可执行程序和直接运行linux环境下的AvoidObs_Search可执行程序时在读取文件时,容器内运行的程序提示无法读取文件。
原因:docker内部镜像的路径和实际运行路径不一样,所以初始化文件的路径对于在docker里的可执行程序来说是无效的,故无法读取数据。
更改为接收POST请求后解决,可以完成通信。
6.2. docker pull失败
docker pull
失败的最常见原因之一是网络连接问题。如果你的网络连接到 Docker Hub 或私有镜像仓库不稳定,可能会导致拉取镜像失败。
1. 找到 Docker 配置文件
Docker 的配置文件 daemon.json
用于配置 Docker 的各种设置。你需要修改这个配置文件,以指定镜像加速器。
-
Linux 系统 :配置文件通常位于
/etc/docker/daemon.json
。 -
Windows 系统 :配置文件通常位于
C:\ProgramData\Docker\config\daemon.json
。 -
MacOS 系统 :配置文件通常位于
/Applications/Docker.app/Contents/Resources/etc/docker/daemon.json
。
如果该文件不存在,可以直接vim /etc/docker/daemon.json
,创建一个新的文件,再进行修改。
2. 配置 Docker 镜像加速器
以下给出我的配置。
bash
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://hub.uuuadc.top",
"https://docker.anyhub.us.kg",
"https://dockerhub.jobcher.com",
"https://dockerhub.icu",
"https://docker.ckyl.me",
"https://docker.awsl9527.cn",
"https://mirror.baidubce.com"
]
}
修改完成后,键盘上按esc
退出,英文状态输入:
,再输入wq
保存退出。