Leo的技术分享

记录开发的点滴

C++ 中,对于一个对象或一个表达式,如果可以对其使用调用运算符(()),则称它是可调用的。即,如果 e 是可调用的,则可以这样使用:

1
e(args)

其中,args 是一个逗号分隔的一个或多个参数的列表。

C++ 中可调用对象除了我们熟悉的函数或函数指针外,还包括函数对象以及 lambda 表达式。

本文重点讲述 lambda 表达式。

lambda 表达式表示一个可调用的代码单元,我们可以将其理解为一个未命名的内联函数。一个 lambda 表达式具有如下形式:

1
[capture list](parameter list) -> return type {function body}
  • capture list:捕获列表,lambda 表达式所在函数中定义的局部变量列表
  • parameter list:参数列表
  • return type:返回类型
  • function body:函数体

lambda 表达式可以忽略参数列表和返回类型,但必须包含捕获列表和函数体:

阅读全文 »

函数对象本质上是一个类对象,它重载了函数调用运算符 operator()。调用运算符的函数体实现函数的功能。

例如,我们定义类 LessThan

1
2
3
4
5
6
class LessThan {
public:
bool operator() (const string &s1, const string &s2) {
return s1.size() < s2.size();
}
};

LessThan 包含调用运算符的重载,调用运算符的函数体实现了函数的功能:小于操作。
调用运算符的定义第一次看起来有点令人迷惑,因为出现了两个小括号。第一个小括号:

1
operator()

告诉编译器我们在重载调用运算符。第二个小括号:

1
(const string &s1, const string &s2)

指定传递给调用运算符重载函数的形式参数。

函数对象的定义与普通类对象一样:

阅读全文 »

我们在文章 《使用 docker-compose 搭建 prometheus 监控系统》 的基础上,增加 prometheus 的告警功能。

Prometheus 指标的收集存储与告警是分开的,告警功能由 alertmanager 提供。我们需要在 prometheus 定义告警规则,这些规则可以触发事件,然后传播到 alertmanager。接下来,alertmanager 会决定如何处理相应的警报,并确定使用电子邮件,短信等发出警报。Prometheus 和 alertmanager 的关系如下图所示。

为了在 prometheus 增加 alertmanager 的使用,我们在 docker-compose.yml 增加 alertmanager 容器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
version: '3'
services:
centos1:
image: centos
container_name: centos1
restart: always
ports:
- "9101:9100"
volumes:
- ~/code/docker/prometheus/node_exporter:/root
command: /root/node_exporter

centos2:
image: centos
container_name: centos2
restart: always
ports:
- "9102:9100"
volumes:
- ~/code/docker/prometheus/node_exporter:/root
command: /root/node_exporter

prometheus:
image: prom/prometheus
container_name: prometheus
restart: always
ports:
- "9090:9090"
volumes:
- ~/code/docker/prometheus/prometheus:/etc/prometheus
- ~/code/docker/prometheus/prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'

grafana:
image: grafana/grafana
container_name: grafana
restart: always
ports:
- "3000:3000"
volumes:
- ~/code/docker/prometheus/grafana_data:/var/lib/grafana

alertmanager:
image: prom/alertmanager
container_name: alertmanager
restart: always
ports:
- "9093:9093"
volumes:
- ~/code/docker/prometheus/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
command:
- '--config.file=/etc/alertmanager/alertmanager.yml'
阅读全文 »

Prometheus 是当前一套非常流行的开源监控和报警系统,于 2016 年加入了 Clound Native Computing Foundation,是继 kubernates 之后的第二个托管项目。

本文讲述如何使用 docker 快速搭建 prometheus 监控系统。

概览

本文的实验环境为 Mac OS,监控系统主要是用来监控两台 CentOS 主机资源使用情况。搭建的监控系统包括以下软件:

  • prometheus:负责收集和存储时间序列数据
  • node-exporter:负责暴露主机 metrics 数据给 prometheus
  • grafana:负责展示数据

它们的关系如下图所示:

node-exporter

为方便操作,我们先创建 prometheus 目录,用于存放此次实验的文件,例如,笔者创建的目录为 ~/code/docker/prometheus

阅读全文 »

我们知道,gitlab 可以用来管理 git 提交的源代码,此外,gitlab 还集成了 docker registry 的功能,可以用来作为一个 docker 镜像私有仓库使用。

启用 gitlab registry 功能

我们假设已安装好 gitlab,具体安装可参考 《使用 docker 安装 gitlab》

Gitlab 默认不打开 docker registry 的功能,需要修改配置打开。

修改配置 /etc/gitlab/gitlab.rb 文件,将 registry_external_url 的值修改为 http://127.0.0.1:4567

1
registry_external_url 'http://127.0.0.1:4567'

registry_external_url 这个地址是我们使用 docker 命令进行 pull 或者 push 镜像的仓库地址。

重启 gitlab 后,可以在 gitlab 左侧面板看到 Container Registry 的菜单。

上传镜像

我们以一个常见的 flask 应用为例,说明如何向 gitlab registry 上传镜像。

Flask 应用源代码包括以下代码:

阅读全文 »

Gitlab 作为开源的 git 代码仓库,功能强大,使用起来非常方便。本文讲述如何使用 docker 来安装 gitlab。

本文假定已安装好 docker,可以输入 docker --version 来验证是否已正常安装,输出:

Docker version 19.03.5, build 633a0ea

使用 docker run 命令安装

为方便安装,我们先拉取最新版本的 gitlab 社区版本镜像:

1
docker pull gitlab/gitlab-ce:latest

然后,使用 docker run 运行 gitlab:

1
2
3
4
5
6
7
8
9
docker run --detach \
--hostname 127.0.0.1 \
--publish 443:443 --publish 80:80 --publish 22:22 \
--name gitlab \
--restart always \
--volume /Users/lihao/code/docker/gitlab-ce/config:/etc/gitlab \
--volume /Users/lihao/code/docker/gitlab-ce/logs:/var/log/gitlab \
--volume /Users/lihao/code/docker/gitlab-ce/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest

docker run 命令使用了多个参数,这些参数的作用如下:

阅读全文 »

Docker compose (以下简称为 compose)可用于定义和运行多容器 docker 应用程序。
通过 compose,我们可以使用 YAML 文件来配置应用程序的服务(services),然后只需要通过一个命令,就可以将配置的所有服务启动起来。

使用 compose 只需要三步:

  1. 使用 Dockerfile 定义应用的环境,以便于可以任何地方复制应用的环境
  2. 使用 docker-compose.yml 定义构成应用的服务,以便于它们可以在隔离的环境中一起运行
  3. 运行 docker-compose up 命令,这时 compose 会启动并运行整个应用程序

安装

对于 Mac 系统 和 Windows 系统,安装 docker 桌面端时, compose 已经捆绑安装了。对于 Linux 系统安装 compose 也不麻烦,可以参考官方安装文档 https://docs.docker.com/compose/install/

可以通过以下命令来测试 compose 安装是否成功:

1
docker-compose --version

输出:

docker-compose version 1.24.1, build 4667896b

实践:以 Flask 应用为例

我们以一个 Flask 应用程序为例,说明如何使用 compose 来配置相关的服务。

步骤一:编写源代码

  1. 创建源代码目录 composetest
1
2
mkdir composetest
cd composetest
阅读全文 »

概览

默认情况下,在 docker 容器(container)内创建的文件或产生的数据都只是保存在容器的可写层,这意味着当容器不存在时,容器内产生的数据也没有保存下来。

Docker 提供两种容器数据持久化的方法,使用这两种方法即使容器不存在时,数据也能持久化下来:

  • Bind mount:bind mount 可以是宿主机(host)文件系统的任意目录或文件,除了 docker 容器可以访问,宿主机上也可以对这些目录或文件读写操作
  • Volume:volume 数据持久化在宿主机文件系统 /var/lib/docker/volumes/ 目录下,volume 数据由 docker 进行管理,外部不要对 volume 数据进程修改。 Volume 方式是 docker 官方推荐的数据持久化方式。

另外,如果 docker 运行在 Linux 宿主机,还可以使用 tmpfs mounttmpfs mount 的数据只是保存在宿主机的内存中,并没有持久化到硬盘。

Docker 容器与宿主机数据共享的方式如下图所示:

无论使用哪种方式,对于 docker 容器来说,这些数据都被看作成一个目录或文件,数据的使用方式是一样的。

Bind mount

Bind mount 方式是 docker 早期使用的容器与宿主机数据共享的方式,可以实现将宿主机上的文件或目录挂载(mount)到 docker 容器中使用。

相对于 volume 方式,bind mount 方式存在不少的局限。例如,bind mount 在 Linux 和 Windows 操作系统下不可移植。因此 docker 官方推荐使用 volume 方式。

为了便于说明 docker 数据共享的特点,我们以 busybox 镜像为例进行操作演示。

例如,使用 docker run -v 命令来将将宿主机的 /Users/lihao/code/docker/busybox 目录挂载到容器的 /databind 目录:

阅读全文 »

之前曾经写过 Python 使用 gRPC 收发消息的教程,可以参考文章 《体验 gRPC 那些事儿》。最近计划在 C++ 项目中使用 gRPC,故写一篇文章来记录一下如何使用 C++ 语言来实现一个简单的 gRPC 服务端和客户端程序。

本教程需要先安装 gRPC,有关 gRPC 的安装教程可以参考文章 《CentOS 7 安装 gRPC》《体验 gRPC 那些事儿》

本文涉及的程序包括四部分,分别是客户端源代码 client.cc,服务端源代码 server.cc,proto 文件 mathtest.proto 以及 Makefile。

Makefile

Makefile 的作用是编译源代码,Makefile 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
LDFLAGS = -L/usr/local/lib `pkg-config --libs protobuf grpc++`\
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
-ldl

CXX = g++
CPPFLAGS += `pkg-config --cflags protobuf grpc`
CXXFLAGS += -std=c++11

GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`

all: client server

client: mathtest.pb.o mathtest.grpc.pb.o client.o
$(CXX) $^ $(LDFLAGS) -o $@

server: mathtest.pb.o mathtest.grpc.pb.o server.o
$(CXX) $^ $(LDFLAGS) -o $@

%.grpc.pb.cc: %.proto
protoc --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<

%.pb.cc: %.proto
protoc --cpp_out=. $<

clean:
rm -f *.o *.pb.cc *.pb.h client server
阅读全文 »

数据存储包括三种类型,分别是块存储,文件存储和对象存储。有关这三种类型的差别,可以参考 对象存储、文件存储和块存储的区别

MioIO 是一个开源的分布式对象存储系统,非常适合于存储大容量非结构化的数据,例如图片,视频,日志文件,备份数据等。本文讲述如何快速搭建 MioIO 服务端和客户端,以便于对 MioIO 有个概要了解。

MinIO 服务端安装

MioIO 是一个非常轻量级的对象存储系统,可以使用 Docker 快速搭建 MinIO 服务。

1
2
docker pull minio/minio
docker run -p 9000:9000 minio/minio server /data

执行以上命令,就启动了 MinIO 服务。有关使用 Docker 启动 MinIO 的详细介绍,可以参考链接 https://docs.min.io/docs/minio-docker-quickstart-guide

打开浏览器,输入地址 http://127.0.0.1:9000/,输入用户名 minioadmin 和密码 minioadmin,便进入 MinIO 的管理页面。

阅读全文 »
0%