akn*_*ds1 78 amazon-ecs docker docker-registry
一旦所述图像在相应的注册表中更新后,使我的Amazon ECS任务更新其Docker镜像的正确方法是什么?
Dim*_*ima 59
如果您的任务在服务下运行,则可以强制执行新部署.这会强制重新评估任务定义并拉出新的容器图像.
aws ecs update-service --cluster <cluster name> --service <service name> --force-new-deployment
Run Code Online (Sandbox Code Playgroud)
Sam*_*arp 56
每次启动任务(通过StartTask和RunTaskAPI调用或自动启动作为服务的一部分),在ECS代理将执行docker pull的image你设置的任务定义.如果每次推送到注册表时都使用相同的映像名称(包括标记),则应该能够通过运行新任务来运行新映像.请注意,如果Docker因任何原因(例如,网络问题或身份验证问题)无法访问注册表,则ECS代理将尝试使用缓存的映像; 如果要在更新映像时避免使用缓存图像,则每次都要将不同的标记推送到注册表,并在运行新任务之前相应地更新任务定义.
Nea*_*eal 21
注册新任务定义并更新服务以使用新任务定义是AWS推荐的方法.最简单的方法是:
本教程提供了更多详细信息,并描述了上述步骤如何适用于端到端产品开发过程.
完全披露:本教程以Bitnami的容器为特色,我为Bitnami工作.然而,这里表达的想法是我自己的,而不是Bitnami的意见.
Z.W*_*Wei 12
有两种方法可以做到这一点。
首先,使用 AWS CodeDeploy。您可以在 ECS 服务定义中配置蓝/绿部署部分。这包括一个 CodeDeployRoleForECS、另一个用于交换机的 TargetGroup 和一个测试侦听器(可选)。AWS ECS 将创建 CodeDeploy 应用程序和部署组,并将这些 CodeDeploy 资源与您的 ECS 集群/服务和您的 ELB/目标组链接起来。然后就可以使用 CodeDeploy 来发起部署,在部署中需要输入一个 AppSpec,指定使用什么任务/容器来更新什么服务。您可以在此处指定新任务/容器。然后,您会看到新的实例在新的 TargetGroup 中启动,旧的 TargetGroup 与 ELB 断开连接,很快注册到旧 TargetGroup 的旧实例将被终止。
这听起来非常复杂。实际上,由于/如果您在 ECS 服务上启用了自动缩放,那么一个简单的方法是使用控制台或 cli 强制进行新部署,就像这里的一位绅士指出的那样:
aws ecs update-service --cluster <cluster name> --service <service name> --force-new-deployment
通过这种方式,您仍然可以使用“滚动更新”部署类型,如果一切正常,ECS 将简单地启动新实例并耗尽旧实例,而不会导致您的服务停机。不好的一面是你失去了对部署的良好控制,如果出现错误,你无法回滚到以前的版本,这会破坏正在进行的服务。但这是一个非常简单的方法。
顺便说一句,不要忘记为最小健康百分比和最大百分比设置适当的数字,例如 100 和 200。
小智 7
遇到同样的问题。花费数小时后,完成了这些用于自动部署更新映像的简化步骤:
1.ECS 任务定义更改:为了更好地理解,假设您已经创建了一个包含以下详细信息的任务定义(注意:这些数字会根据您的任务定义相应地更改):
launch_type = EC2
desired_count = 1
Run Code Online (Sandbox Code Playgroud)
然后您需要进行以下更改:
deployment_minimum_healthy_percent = 0 //this does the trick, if not set to zero the force deployment wont happen as ECS won't allow to stop the current running task
deployment_maximum_percent = 200 //for allowing rolling update
Run Code Online (Sandbox Code Playgroud)
2.将您的图像标记为 < your-image-name>:latest。最新的密钥负责被相应的 ECS 任务拉取。
sudo docker build -t imageX:master . //build your image with some tag
sudo -s eval $(aws ecr get-login --no-include-email --region us-east-1) //login to ECR
sudo docker tag imageX:master <your_account_id>.dkr.ecr.us-east-1.amazonaws.com/<your-image-name>:latest //tag your image with latest tag
Run Code Online (Sandbox Code Playgroud)
3.Push到图片到ECR
sudo docker push <your_account_id>.dkr.ecr.us-east-1.amazonaws.com/<your-image-name>:latest
Run Code Online (Sandbox Code Playgroud)
4.apply force-部署
sudo aws ecs update-service --cluster <your-cluster-name> --service <your-service-name> --force-new-deployment --region us-east-1
Run Code Online (Sandbox Code Playgroud)
注意:我已经编写了所有命令,假设区域是us-east-1。只需在实施时将其替换为您各自的区域即可。
I created a script for deploying updated Docker images to a staging service on ECS, so that the corresponding task definition refers to the current versions of the Docker images. I don't know for sure if I'm following best practices, so feedback would be welcome.
For the script to work, you need either a spare ECS instance or a deploymentConfiguration.minimumHealthyPercent value so that ECS can steal an instance to deploy the updated task definition to.
My algorithm is like this:
我的代码粘贴在下面:
#!/usr/bin/env python3
import subprocess
import sys
import os.path
import json
import re
import argparse
import tempfile
_root_dir = os.path.abspath(os.path.normpath(os.path.dirname(__file__)))
sys.path.insert(0, _root_dir)
from _common import *
def _run_ecs_command(args):
run_command(['aws', 'ecs', ] + args)
def _get_ecs_output(args):
return json.loads(run_command(['aws', 'ecs', ] + args, return_stdout=True))
def _tag_image(tag, qualified_image_name, purge):
log_info('Tagging image \'{}\' as \'{}\'...'.format(
qualified_image_name, tag))
log_info('Pulling image from registry in order to tag...')
run_command(
['docker', 'pull', qualified_image_name], capture_stdout=False)
run_command(['docker', 'tag', '-f', qualified_image_name, '{}:{}'.format(
qualified_image_name, tag), ])
log_info('Pushing image tag to registry...')
run_command(['docker', 'push', '{}:{}'.format(
qualified_image_name, tag), ], capture_stdout=False)
if purge:
log_info('Deleting pulled image...')
run_command(
['docker', 'rmi', '{}:latest'.format(qualified_image_name), ])
run_command(
['docker', 'rmi', '{}:{}'.format(qualified_image_name, tag), ])
def _register_task_definition(task_definition_fpath, purge):
with open(task_definition_fpath, 'rt') as f:
task_definition = json.loads(f.read())
task_family = task_definition['family']
tag = run_command([
'git', 'rev-parse', '--short', 'HEAD', ], return_stdout=True).strip()
for container_def in task_definition['containerDefinitions']:
image_name = container_def['image']
_tag_image(tag, image_name, purge)
container_def['image'] = '{}:{}'.format(image_name, tag)
log_info('Finding existing task definitions of family \'{}\'...'.format(
task_family
))
existing_task_definitions = _get_ecs_output(['list-task-definitions', ])[
'taskDefinitionArns']
for existing_task_definition in [
td for td in existing_task_definitions if re.match(
r'arn:aws:ecs+:[^:]+:[^:]+:task-definition/{}:\d+'.format(
task_family),
td)]:
log_info('Deregistering task definition \'{}\'...'.format(
existing_task_definition))
_run_ecs_command([
'deregister-task-definition', '--task-definition',
existing_task_definition, ])
with tempfile.NamedTemporaryFile(mode='wt', suffix='.json') as f:
task_def_str = json.dumps(task_definition)
f.write(task_def_str)
f.flush()
log_info('Registering task definition...')
result = _get_ecs_output([
'register-task-definition',
'--cli-input-json', 'file://{}'.format(f.name),
])
return '{}:{}'.format(task_family, result['taskDefinition']['revision'])
def _update_service(service_fpath, task_def_name):
with open(service_fpath, 'rt') as f:
service_config = json.loads(f.read())
services = _get_ecs_output(['list-services', ])[
'serviceArns']
for service in [s for s in services if re.match(
r'arn:aws:ecs:[^:]+:[^:]+:service/{}'.format(
service_config['serviceName']),
s
)]:
log_info('Updating service with new task definition...')
_run_ecs_command([
'update-service', '--service', service,
'--task-definition', task_def_name,
])
parser = argparse.ArgumentParser(
description="""Deploy latest Docker image to staging server.
The task definition file is used as the task definition, whereas
the service file is used to configure the service.
""")
parser.add_argument(
'task_definition_file', help='Your task definition JSON file')
parser.add_argument('service_file', help='Your service JSON file')
parser.add_argument(
'--purge_image', action='store_true', default=False,
help='Purge Docker image after tagging?')
args = parser.parse_args()
task_definition_file = os.path.abspath(args.task_definition_file)
service_file = os.path.abspath(args.service_file)
os.chdir(_root_dir)
task_def_name = _register_task_definition(
task_definition_file, args.purge_image)
_update_service(service_file, task_def_name)
Run Code Online (Sandbox Code Playgroud)
import sys
import subprocess
__all__ = ['log_info', 'handle_error', 'run_command', ]
def log_info(msg):
sys.stdout.write('* {}\n'.format(msg))
sys.stdout.flush()
def handle_error(msg):
sys.stderr.write('* {}\n'.format(msg))
sys.exit(1)
def run_command(
command, ignore_error=False, return_stdout=False, capture_stdout=True):
if not isinstance(command, (list, tuple)):
command = [command, ]
command_str = ' '.join(command)
log_info('Running command {}'.format(command_str))
try:
if capture_stdout:
stdout = subprocess.check_output(command)
else:
subprocess.check_call(command)
stdout = None
except subprocess.CalledProcessError as err:
if not ignore_error:
handle_error('Command failed: {}'.format(err))
else:
return stdout.decode() if return_stdout else None
Run Code Online (Sandbox Code Playgroud)
如果 docker 图像标签相同,以下对我有用:
以下 api 也有效:
aws ecs update-service --cluster <cluster_name> --service <service_name> --force-new-deployment
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
35838 次 |
| 最近记录: |