मेरे अमेज़ॅन ईसीएस कार्यों को अपनी डॉकर छवियों को अपडेट करने के लिए सही दृष्टिकोण क्या है , एक बार कहा छवियों को इसी रजिस्ट्री में अपडेट किया गया है?
मेरे अमेज़ॅन ईसीएस कार्यों को अपनी डॉकर छवियों को अपडेट करने के लिए सही दृष्टिकोण क्या है , एक बार कहा छवियों को इसी रजिस्ट्री में अपडेट किया गया है?
जवाबों:
यदि आपका कार्य किसी सेवा के अंतर्गत चल रहा है, तो आप नई तैनाती के लिए बाध्य कर सकते हैं। यह कार्य परिभाषा को पुनर्मूल्यांकन करने के लिए मजबूर करता है और नई कंटेनर छवि को खींचा जाता है।
aws ecs update-service --cluster <cluster name> --service <service name> --force-new-deployment
हर बार जब आप (के माध्यम से या तो कार्य प्रारंभ करें StartTask
और RunTask
API कॉल या कि एक सेवा के भाग के रूप में स्वचालित रूप से शुरू कर दिया गया है), ईसीएस एजेंट एक प्रदर्शन करेंगे docker pull
की image
अपने कार्य परिभाषा में निर्दिष्ट आप। यदि आप प्रत्येक बार रजिस्ट्री पर धकेलने के लिए एक ही छवि नाम (टैग सहित) का उपयोग करते हैं, तो आपको एक नया कार्य चलाने में नई छवि चलाने में सक्षम होना चाहिए। ध्यान दें कि यदि डॉकर किसी भी कारण से रजिस्ट्री तक नहीं पहुंच सकता है (उदाहरण के लिए, नेटवर्क समस्याएं या प्रमाणीकरण मुद्दे), तो ईसीएस एजेंट एक कैश्ड छवि का उपयोग करने का प्रयास करेगा; अगर आप अपनी छवि को अपडेट करने के दौरान कैश्ड छवियों के उपयोग से बचना चाहते हैं, तो आप हर बार अपनी रजिस्ट्री में एक अलग टैग डालना चाहते हैं और नए कार्य को चलाने से पहले अपनी कार्य परिभाषा को अपडेट कर सकते हैं।
अद्यतन: इस व्यवहार को अब ECS_IMAGE_PULL_BEHAVIOR
ECS एजेंट पर सेट पर्यावरण चर के माध्यम से देखा जा सकता है । देखें प्रलेखन जानकारी के लिए। लेखन के समय के अनुसार, निम्नलिखित सेटिंग्स समर्थित हैं:
आपके कंटेनर इंस्टेंस के लिए पुल छवि प्रक्रिया को अनुकूलित करने के लिए उपयोग किया जाने वाला व्यवहार। निम्नलिखित वैकल्पिक व्यवहारों का वर्णन करता है:
यदि
default
निर्दिष्ट किया गया है, तो छवि को दूरस्थ रूप से खींच लिया गया है। यदि छवि पुल विफल हो जाता है, तो कंटेनर उदाहरण पर कैश्ड छवि का उपयोग करता है।यदि
always
निर्दिष्ट किया गया है, तो छवि को हमेशा दूर से खींचा जाता है। यदि छवि पुल विफल हो जाता है, तो कार्य विफल हो जाता है। यह विकल्प यह सुनिश्चित करता है कि छवि का नवीनतम संस्करण हमेशा खींचा जाए। किसी भी कैश्ड चित्र को अनदेखा किया जाता है और स्वचालित छवि सफाई प्रक्रिया के अधीन होता है।यदि
once
निर्दिष्ट किया गया है, तो छवि को केवल दूरस्थ रूप से खींचा जाता है यदि यह उसी कंटेनर उदाहरण पर पिछले कार्य द्वारा खींचा नहीं गया है या यदि कैश की गई छवि को स्वचालित छवि सफाई प्रक्रिया द्वारा हटा दिया गया था। अन्यथा, उदाहरण पर कैश्ड छवि का उपयोग किया जाता है। यह सुनिश्चित करता है कि कोई अनावश्यक छवि नहीं खींची जाती है।यदि
prefer-cached
निर्दिष्ट किया गया है, तो कोई कैश की गई छवि नहीं होने पर छवि को दूरस्थ रूप से खींच लिया जाता है। अन्यथा, उदाहरण पर कैश्ड छवि का उपयोग किया जाता है। कैश्ड छवि को हटाया नहीं जाता है यह सुनिश्चित करने के लिए कंटेनर के लिए स्वचालित छवि सफाई अक्षम है।
/var/log/ecs
।
नई कार्य परिभाषा दर्ज करना और नई कार्य परिभाषा का उपयोग करने के लिए सेवा को अपडेट करना AWS द्वारा अनुशंसित दृष्टिकोण है। इसके लिए सबसे आसान तरीका है:
इस ट्यूटोरियल में अधिक विवरण है और बताता है कि उपरोक्त चरण एंड-टू-एंड उत्पाद विकास प्रक्रिया में कैसे फिट होते हैं।
पूर्ण प्रकटीकरण: इस ट्यूटोरियल में बिटनामी के कंटेनर हैं और मैं बिटनामी के लिए काम करता हूं। हालाँकि यहाँ व्यक्त विचार मेरे अपने हैं और बिटनामी के मत नहीं।
इसे करने के दो तरीके हैं।
सबसे पहले, AWS CodeDeploy का उपयोग करें। आप ECS सेवा परिभाषा में ब्लू / ग्रीन परिनियोजन अनुभागों को कॉन्फ़िगर कर सकते हैं। इसमें एक CodeDeployRoleForECS, स्विच के लिए एक और TargetGroup और एक परीक्षण श्रोता (वैकल्पिक) शामिल हैं। AWS ECS CodeDeploy एप्लिकेशन और परिनियोजन समूह बनाएगा और आपके लिए इन ECS क्लस्टर / सेवा और आपके ELB / TargetGroups के साथ इन CodeDeploy संसाधनों को लिंक करेगा। तब आप एक परिनियोजन आरंभ करने के लिए CodeDeploy का उपयोग कर सकते हैं, जिसमें आपको एक AppSpec दर्ज करने की आवश्यकता होती है जो निर्दिष्ट करता है कि किस सेवा / कंटेनर को किस सेवा को अपडेट करने के लिए उपयोग किया जाए। यहां आप अपने नए कार्य / कंटेनर को निर्दिष्ट करते हैं। फिर, आप देखेंगे कि नए टारगेट को नए टारगेटग्रुप में स्पिन किया गया है और पुराने टारगेटग्रुप को एलएलबी में काट दिया गया है, और जल्द ही पुराने टारगेटग्रुप में पंजीकृत पुराने इंस्टेंसेस को समाप्त कर दिया जाएगा।
यह बहुत जटिल लगता है। वास्तव में, चूंकि / यदि आपने अपनी ईसीएस सेवा पर ऑटो स्केलिंग सक्षम की है, तो ऐसा करने का एक सरल तरीका यह है कि कंसोल या क्ली का उपयोग करके एक नई तैनाती को मजबूर करना है, जैसे एक सज्जन ने यहां बताया है:
aws ecs update-service --cluster <cluster name> --service <service name> --force-new-deployment
इस तरह आप अभी भी "रोलिंग अपडेट" परिनियोजन प्रकार का उपयोग कर सकते हैं, और ईसीएस बस नए उदाहरणों को स्पिन करेगा और सब कुछ ठीक होने पर आपकी सेवा के बिना डाउनटाइम वाले पुराने को सूखा देगा। खराब पक्ष यह है कि आप परिनियोजन पर ठीक से नियंत्रण खो देते हैं और त्रुटि होने पर पिछले संस्करण में वापस नहीं लौटते हैं और इससे जारी सेवा टूट जाएगी। लेकिन यह एक बहुत ही सरल तरीका है।
BTW, न्यूनतम स्वस्थ प्रतिशत और अधिकतम प्रतिशत, जैसे 100 और 200 के लिए उचित संख्या निर्धारित करना न भूलें।
मैंने अद्यतन डॉकरों की छवियों को ईसीएस पर एक मचान सेवा में तैनात करने के लिए एक स्क्रिप्ट बनाई , ताकि संबंधित कार्य परिभाषा डोकर छवियों के वर्तमान संस्करणों को संदर्भित करे। मुझे यकीन नहीं है कि अगर मैं सर्वोत्तम प्रथाओं का पालन कर रहा हूं, तो प्रतिक्रिया का स्वागत किया जाएगा।
काम करने के लिए स्क्रिप्ट के लिए, आपको या तो एक अतिरिक्त ईसीएस उदाहरण या एक deploymentConfiguration.minimumHealthyPercent
मूल्य की आवश्यकता है ताकि ईसीएस अपडेट की गई परिभाषा को तैनात करने के लिए एक उदाहरण चोरी कर सके।
मेरा एल्गोरिथ्म इस तरह है:
मेरा कोड नीचे चिपकाया गया:
#!/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)
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
मेरे लिए काम के मामले में बाद में docker की इमेज टैग समान है:
एक ही मुद्दे में भाग गया। घंटों बिताने के बाद, अद्यतन छवि की स्वचालित तैनाती के लिए इन सरलीकृत चरणों का निष्कर्ष निकाला है:
1.ECS कार्य परिभाषा में परिवर्तन: एक बेहतर समझ के लिए, मान लें कि आपने नीचे विवरण के साथ एक कार्य परिभाषा बनाई है (ध्यान दें: ये संख्या आपके कार्य परिभाषा के अनुसार बदल जाएगी):
launch_type = EC2
desired_count = 1
फिर आपको निम्नलिखित परिवर्तन करने की आवश्यकता है:
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
2. अपनी छवि को < अपनी छवि-नाम>: नवीनतम के रूप में रखें । नवीनतम कुंजी संबंधित ईसीएस कार्य द्वारा खींचे जाने का ख्याल रखती है।
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
3. छवि को ECR में रखें
sudo docker push <your_account_id>.dkr.ecr.us-east-1.amazonaws.com/<your-image-name>:latest
4. पूरी तरह से तैनाती
sudo aws ecs update-service --cluster <your-cluster-name> --service <your-service-name> --force-new-deployment --region us-east-1
नोट: मैंने सभी आदेशों को इस क्षेत्र को हम-पूरब -1 मानकर लिखा है । लागू करते समय इसे अपने संबंधित क्षेत्र से बदल दें।
AWS cli का उपयोग करके मैंने ऊपर दिए गए सुझाव के अनुसार अपडेट-सेवा की कोशिश की। ईसीआर से नवीनतम डॉकटर नहीं उठाए। अंत में, मैंने अपनी एन्सिबल प्लेबुक को फिर से चलाया जो कि ECS क्लस्टर बनाया। जब ecs_taskdefinition चलता है, तो कार्य परिभाषा का संस्करण टकरा जाता है। फिर सब अच्छा है। नई डॉकटर छवि को उठाया जाता है।
सत्यता से यह सुनिश्चित नहीं होता है कि टास्क वर्जन में बदलाव के कारण रिडाइपल बाध्य हो जाता है, या यदि ecs_service का उपयोग करने वाली प्लेबुक कार्य को पुनः लोड करने का कारण बनती है।
अगर किसी को दिलचस्पी है, तो मुझे अपनी प्लेबुक के एक संचित संस्करण को प्रकाशित करने की अनुमति मिल जाएगी।
अच्छी तरह से मैं भी इसे करने का एक स्वचालित तरीका खोजने की कोशिश कर रहा हूं, जो कि ईसीआर में बदलावों को आगे बढ़ा रहा है और फिर नवीनतम टैग को सेवा द्वारा उठाया जाना चाहिए। सही आप इसे अपने क्लस्टर से अपनी सेवा के लिए कार्य रोककर मैन्युअल रूप से कर सकते हैं। नए कार्य अपडेट किए गए ईसीआर कंटेनरों को खींचेंगे।
निम्नलिखित आदेशों ने मेरे लिए काम किया
docker build -t <repo> .
docker push <repo>
ecs-cli compose stop
ecs-cli compose start