我正在尝试使用Terraform创建一个Docker Swarm集群,我创建了1个管理器和3个工作节点。我安装了Docker并启动了Docker Swarm并创建了管理器令牌。
如何将密钥从管理器转发到工作线程节点、AWS 中运行的所有服务器以及在本地计算机上运行terrafrom apply
命令?
我有多个限制,因为我无法为此特定任务请求新服务。
抱歉没有提及,我必须使用动态IP,因为整个环境都是使用动态IP构建的,并且没有IP锁定到任何特定资源。
群管理器需要一种在初始化后将工作线程令牌传递给工作线程的方法。最好的方法是让群管理器的用户数据触发器生成令牌,并将其放入他们都可以访问的共享存储中。在 AWS 中,最简单的方法是使用 AWS SSM 参数存储,它允许您存储小型字符串(可选(加密并由普通 IAM 权限支持。
您需要通过 IAM 实例配置文件向群管理器实例授予权限,以将令牌写入类似/swarm/token/worker
的内容,然后允许工作线程实例读取同一令牌的权限。
然后在经理的用户数据脚本中,您需要具有类似以下内容的内容:
WORKER_TOKEN=$(docker swarm join-token worker)
aws ssm put-parameter --region us-west-2 --name '/swarm/token/worker' --type SecureString --value "${WORKER_TOKEN}"
在工作人员的用户数据脚本中,您需要等效的读取和执行:
WORKER_TOKEN=$(aws ssm get-parameter --region us-west-2 --name '/swarm/token/worker' --with-decryption --query 'Parameter.Value' --output text)
eval "${WORKER_TOKEN}"
还有一个社区模块,其中包含如何在 AWS 上运行 Docker Swarm 的示例,该示例依赖于将秘密令牌放入 S3,然后使用 userdata 脚本在工作线程节点上检索它。这可能会为您提供有关如何让 Swarm 集群在 AWS 上正常运行的更多提示。
我通过以下步骤解决了这个问题:
AWS
中主节点的静态 ip
。- 我在主服务器上运行的
nodejs
中创建了简单的 api rest 应用程序。此api
接受来自其他节点的请求并返回令牌密钥。
这是我使用的基本代码:
const { exec } = require("child_process");
const execFunction = (command, res, returnOutput) => {
exec(command, (error, stdout, stderr) => {
if (stdout) {
returnOutput ? res.status(200).send(stdout) : res.sendStatus(204);
}
else if (stderr) {
res.status(400).send({ error: stderr });
}
else if (error !== null) {
res.status(400).send({ error: error });
}
else {
res.sendStatus(500);
}
});
};
app.get("/api/dockerswarm/token/:type", (req, res) => {
const { type } = req.params;
if (!type || (type !== "worker" && type !== "manager")) {
res.status(400).send({ message: 'invalid token type supplied (manager|worker)' });
}
else {
const dockerCommand = `docker swarm join-token ${type} | sed -n 3p | grep -Po 'docker swarm join --token \K[^\s]*'`;
execFunction(dockerCommand, res, true);
}
});
现在,其他机器可以向主节点请求令牌,并且可以连接到Swarm(我在userdata中插入了代码,用于检查节点是否已在Swarm中,否则请求令牌(。
这里有完整的代码(包括我在 AWS Swarm 中使用的一些其他文件(。
以为我会在这里分享我正在使用的东西。
一般概念是,第一个节点成为管理器并在 ssm中注册其连接令牌。(可能应该加密,但这是我们的开发脚本(
其他节点将进入一个循环,它们尝试拉下令牌并向群注册 - 如果这不起作用,它们将进入睡眠状态并重试。
资源定义
resource "aws_instance" "swarm" {
ami = "ami-0cff7528ff583bf9a"
instance_type = "t2.small"
count = var.swarm_manager_node_count + var.swarm_worker_node_count
key_name = "MY-SSH-KEY"
vpc_security_group_ids = var.swarm_security_group_ids
subnet_id = var.swarm_subnet_id
tags = {
Name = "swarm-node-${count.index}"
}
# Use a file template to configure the user_data
# by declaring vars we can inject these into the final script
# that will be run.
user_data = templatefile("${path.module}/user_data.tftpl", {
node_number = count.index
node_name = "swarm-node-${count.index}"
WORKER_TOKEN = ""
MANAGER_TOKEN = ""
SWARM_AWS_ACCESS_KEY_ID = var.aws_access_key_id
SWARM_AWS_SECRET_ACCESS_KEY = var.aws_secret_access_key
SWARM_AWS_REGION = "us-east-1"
SWARM_MANAGER_NODE_COUNT = var.swarm_manager_node_count
}
)
}
user_data
我有一个脚本user_data.tftpl
#!/bin/bash -xe
# Install the docker
yum update -y
# install Docker
yum install docker -y
# add ec2-user to docker group
usermod -a -G docker ec2-user
# Start / enable docker
systemctl enable docker.service
systemctl start docker.service
# If we are NODE0 we are a manager
echo ${node_number}
export AWS_DEFAULT_REGION=${SWARM_AWS_REGION}
export AWS_ACCESS_KEY_ID=${SWARM_AWS_ACCESS_KEY_ID}
export AWS_SECRET_ACCESS_KEY=${SWARM_AWS_SECRET_ACCESS_KEY}
aws configure set aws_access_key_id ${SWARM_AWS_ACCESS_KEY_ID}
aws configure set aws_secret_access_key ${SWARM_AWS_SECRET_ACCESS_KEY}
aws configure set default_region ${SWARM_AWS_REGION}
if [[ "${node_number}" == "0" ]]; then
docker swarm init
export MANAGER_TOKEN=$(docker swarm join-token manager | grep token | xargs echo -n)
export WORKER_TOKEN=$(docker swarm join-token worker | grep token | xargs echo -n)
echo "Storing Manager Token [$MANAGER_TOKEN]"
echo "Storing Worker Token [$WORKER_TOKEN]"
aws ssm put-parameter
--region us-east-1
--name '/swarm/token/worker'
--type String
--overwrite
--value "$WORKER_TOKEN"
aws ssm put-parameter
--region us-east-1
--name '/swarm/token/manager'
--type String
--overwrite
--value "$MANAGER_TOKEN"
elif [[ "${node_number}" -le "${SWARM_MANAGER_NODE_COUNT}" ]]; then
JOIN_STATUS=1
while [ $JOIN_STATUS -ne 0 ]; do
docker swarm leave || true
$(aws ssm get-parameter
--region us-east-1
--name '/swarm/token/manager'
--query 'Parameter.Value' --output text)
JOIN_STATUS=$?
echo $JOIN_STATUS was
if [[ $JOIN_STATUS -ne 0 ]]; then
echo "Unable to join swarm ... retrying in 10 seconds"
sleep 10
else
echo "Maybe the join worked?"
fi
done
else
JOIN_STATUS=1
while [ $JOIN_STATUS -ne 0 ]; do
docker swarm leave || true
$(aws ssm get-parameter
--region us-east-1
--name '/swarm/token/worker'
--query 'Parameter.Value' --output text)
JOIN_STATUS=$?
if [[ $JOIN_STATUS -ne 0 ]]; then
echo "Unable to join swarm ... retrying in 10 seconds"
sleep 10
else
echo "Maybe the join worked?"
fi
done
fi
我还没有遇到任何重大问题...