この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
CircleCIでのワークフローでコンテナイメージに対して更新を行う際に、イメージファイルが存在せずにエラーとなった事がありました。都合上例外な手順をとったこと、エラーメッセージが難解だったこともあり、イメージファイルが存在しないことが判明するまでにやや時間を必要としました。
備忘録兼ねて、原因判明までのいきさつ、及び対処と、aws-cli経由で表示される独特のエラーメッセージについて書いてみました。
発生していた状況について
CircleCI上にて以下のようなログが出力されていました。
#!/bin/bash -eo pipefail
MANIFEST=$(aws ecr batch-get-image --repository-name repos --image-ids imageTag=master_${CIRCLE_SHA1:0:7} --query images[].imageManifest --output text)
aws ecr put-image --repository-name repos --image-tag prod_${CIRCLE_TAG} --image-manifest "$MANIFEST"
Parameter validation failed: Invalid length for parameter imageManifest, value: 0, valid range: 1-inf
Exited with code exit status 255
imageManifestパラメータのエラーとありますが、value: 0, valid range: 1-inf
がよくわかりません。とりあえずはaws ecr put-image
に渡されている--image-manifest
に問題があると想定し、$MANIFEST
をみてみました。CIRCLE_SHA1については Preparing Environment Variables のログを見ることで確認できます。
aws ecr batch-get-image \
--repository-name repos \
--image-ids imageTag=master_${CIRCLE_SHA1:0:7} \
--query 'images[].imageManifest' \
--output text
結果、何も返ってきませんでした。この時点でイメージが存在していない可能性に気が付きます。
エラーをわかりやすくしてみる
何も分からない状態が早期解消できた感もありますが、どうせなら迷うこと無く直ぐに原因が判るようにしておきたいものです。
when: on_fail
を併用して、以下のようなフローを試してみました。
jobs:
image_exist_check:
docker:
- image: circleci/python:3.7.3
environment:
PIPENV_VENV_IN_PROJECT: true
resource_class: small
executor: aws-cli/default
steps:
- checkout
- setup_remote_docker
- aws-cli/setup
- restore_cache:
key: pipenv-{{ .Branch }}-{{ checksum "Pipfile.lock" }}
- run:
command: |
pipenv sync --dev
exit 1
- run:
name: run tests
when: on_fail
command: |
result=$(aws ecr describe-images --repository-name airflow | jq -r '.imageDetails[].imageTags[] | contains("XXXXXXXXX")' | grep true)
if [ "$result" != "true" ]; then
echo 'Image not found'
fi
workflows:
version: 2
cicd_pipeline:
jobs:
- image_exist_check:
filters:
tags:
ignore: /.*/
branches:
only: image_exist_check
pipenv sync
後に強制終了させています。exit 1にてその後のon_failにて呼ばれて、指定のイメージタグがなければメッセージが残る仕組みです。タグは常にユニークとなるため、trueが2つ以上渡ることはありません。
以下のコマンドによる判定で有無をチェックしています。
result=$(aws ecr describe-images --repository-name airflow | jq -r '.imageDetails[].imageTags[] | contains("XXXXXXXXX")' | grep true)
参考までに、aws ecr describe-images
にてタグが付いているイメージが多く存在する場合は以下のようなレスポンスになります。
% aws ecr describe-images --repository-name airflow | jq -r '.'
{
"imageDetails": [
{
"imageSizeInBytes": 636296435,
"imageDigest": "sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"imageTags": [
"dev_00000001"
],
"registryId": "000000000001",
"repositoryName": "repos",
"imagePushedAt": 1581502156
},
{
"imageSizeInBytes": 673563332,
"imageDigest": "sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"imageTags": [
"prod_v1.0.0",
"master_00000001"
],
"registryId": "000000000000",
"repositoryName": "repos",
"imagePushedAt": 1572410914
},
..
]
}
value: 0, valid range: 1-inf の解
と、上記の流れで原因と対処方法、今後の対処に手間も取らなくなりましたが、CircleCIログ上に残っていたvalue: 0, valid range: 1-inf
が解せません。aws-cli絡みであるとだけ予想はできるので、試しに辿ってみることにしました。
aws-cliのソースからたどり、更にboto3を辿り、更にbotocoreまで辿って見つけたのが以下のコードです。
def range_check(name, value, shape, error_type, errors):
failed = False
min_allowed = float('-inf')
max_allowed = float('inf')
if 'min' in shape.metadata:
min_allowed = shape.metadata['min']
if value < min_allowed:
failed = True
elif hasattr(shape, 'serialization'):
# Members that can be bound to the host have an implicit min of 1
if shape.serialization.get('hostLabel'):
min_allowed = 1
if value < min_allowed:
failed = True
if failed:
errors.report(name, error_type, param=value,
valid_range=[min_allowed, max_allowed])
botocore/validate.py at 8a9b18a3632120181eb186ad0685c208160a4a6a · boto/botocore
Pythonでfloat('inf')
と記述すると、無限大を表すinfが生成されます。float('-inf')
は負の無限大です。
% python
>> float('inf')
inf
>> float('-inf')
-inf</p>
大文字か小文字かは関係なく、例えば "inf"、 "Inf"、 "INFINITY" 、 "iNfINity" は全て正の無限大として使える綴りです。
更にエラーメッセージを実際に返している関数も見てみます。
elif error_type == 'invalid length':
min_allowed = additional['valid_range'][0]
max_allowed = additional['valid_range'][1]
return ('Invalid length for parameter %s, value: %s, valid range: '
'%s-%s' % (name, additional['param'],
min_allowed, max_allowed))
botocore/validate.py at 8a9b18a3632120181eb186ad0685c208160a4a6a · boto/botocore
エラーメッセージは1-infとなっているため、min_allowedが1であり、max_allowedがinfとなるわけです。valueが0だったことを踏まえると、何も渡ってきてないから何か入れろってことですね。
あとがき
手順が例外だったことと、botocore独特のエラーメッセージも独特だったために手間取ってしまいましたが、botocore自体はaws-cliを使う上で避けられないライブラリでもあるため、エラーを確認する際の事前知識を知るいい機会となりました。
CICDのワークフローにaws-cliを利用されている場合に、エラーの対処をどうするべきか迷った際にはbotocoreまで掘り下げてみることもおすすめします。