Reputation: 623
I want to test the deploy of an ECS stack using AWS CLI from a GitLab pipeline.
My test project's core is a variation of the Docker Compose Flask app.
The file app.py
:
import time
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello World!'
with its requirements.txt
:
flask
The Dockerfile
is:
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
and the Docker Compose file is:
version: "3.9"
services:
web:
image: registry.gitlab.com/<MYNAME>/<MYPROJECT>
x-aws-pull_credentials: "<CREDENTIALS>"
ports:
- "5000:5000"
I generate a CloudFormationTemplate.yml
file using an ECS Docker Context (using an ecs
Docker Context myecscontext
, not the default
one) and the command
docker compose convert > CloudFormationTemplate.yml
When I try to deploy on AWS from my local workstation (Win10):
aws cloudformation deploy --template-file CloudFormationTemplate.yml --stack-name test-stack
I get the error
unacceptable character #x0000: special characters are not allowed
in "<unicode string>", position 3
What's wrong? Thanks.
===========
ADDED
Here the CloudFormationTemplate.yml
:
AWSTemplateFormatVersion: 2010-09-09
Resources:
CloudMap:
Properties:
Description: Service Map for Docker Compose project cloudformation
Name: cloudformation.local
Vpc: vpc-XXXXXXXX
Type: AWS::ServiceDiscovery::PrivateDnsNamespace
Cluster:
Properties:
ClusterName: cloudformation
Tags:
- Key: com.docker.compose.project
Value: cloudformation
Type: AWS::ECS::Cluster
Default5000Ingress:
Properties:
CidrIp: 0.0.0.0/0
Description: web:5000/tcp on default network
FromPort: 5000
GroupId:
Ref: DefaultNetwork
IpProtocol: TCP
ToPort: 5000
Type: AWS::EC2::SecurityGroupIngress
DefaultNetwork:
Properties:
GroupDescription: cloudformation Security Group for default network
Tags:
- Key: com.docker.compose.project
Value: cloudformation
- Key: com.docker.compose.network
Value: default
VpcId: vpc-XXXXXXXX
Type: AWS::EC2::SecurityGroup
DefaultNetworkIngress:
Properties:
Description: Allow communication within network default
GroupId:
Ref: DefaultNetwork
IpProtocol: "-1"
SourceSecurityGroupId:
Ref: DefaultNetwork
Type: AWS::EC2::SecurityGroupIngress
LoadBalancer:
Properties:
LoadBalancerAttributes:
- Key: load_balancing.cross_zone.enabled
Value: "true"
Scheme: internet-facing
Subnets:
- subnet-XXXXXXXX
- subnet-XXXXXXXX
- subnet-XXXXXXXX
Tags:
- Key: com.docker.compose.project
Value: cloudformation
Type: network
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
LogGroup:
Properties:
LogGroupName: /docker-compose/cloudformation
Type: AWS::Logs::LogGroup
WebService:
DependsOn:
- WebTCP5000Listener
Properties:
Cluster:
Fn::GetAtt:
- Cluster
- Arn
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentController:
Type: ECS
DesiredCount: 1
LaunchType: FARGATE
LoadBalancers:
- ContainerName: web
ContainerPort: 5000
TargetGroupArn:
Ref: WebTCP5000TargetGroup
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: DefaultNetwork
Subnets:
- subnet-XXXXXXXX
- subnet-XXXXXXXX
- subnet-XXXXXXXX
PlatformVersion: 1.4.0
PropagateTags: SERVICE
SchedulingStrategy: REPLICA
ServiceRegistries:
- RegistryArn:
Fn::GetAtt:
- WebServiceDiscoveryEntry
- Arn
Tags:
- Key: com.docker.compose.project
Value: cloudformation
- Key: com.docker.compose.service
Value: web
TaskDefinition:
Ref: WebTaskDefinition
Type: AWS::ECS::Service
WebServiceDiscoveryEntry:
Properties:
Description: '"web" service discovery entry in Cloud Map'
DnsConfig:
DnsRecords:
- TTL: 60
Type: A
RoutingPolicy: MULTIVALUE
HealthCheckCustomConfig:
FailureThreshold: 1
Name: web
NamespaceId:
Ref: CloudMap
Type: AWS::ServiceDiscovery::Service
WebTCP5000Listener:
Properties:
DefaultActions:
- ForwardConfig:
TargetGroups:
- TargetGroupArn:
Ref: WebTCP5000TargetGroup
Type: forward
LoadBalancerArn:
Ref: LoadBalancer
Port: 5000
Protocol: TCP
Type: AWS::ElasticLoadBalancingV2::Listener
WebTCP5000TargetGroup:
Properties:
Port: 5000
Protocol: TCP
Tags:
- Key: com.docker.compose.project
Value: cloudformation
TargetType: ip
VpcId: vpc-XXXXXXXX
Type: AWS::ElasticLoadBalancingV2::TargetGroup
WebTaskDefinition:
Properties:
ContainerDefinitions:
- Command:
- XXXXXXXX.compute.internal
- cloudformation.local
Essential: false
Image: docker/ecs-searchdomain-sidecar:1.0
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group:
Ref: LogGroup
awslogs-region:
Ref: AWS::Region
awslogs-stream-prefix: cloudformation
Name: Web_ResolvConf_InitContainer
- DependsOn:
- Condition: SUCCESS
ContainerName: Web_ResolvConf_InitContainer
Essential: true
Image: registry.gitlab.com/MYUSER/cloudformation
LinuxParameters: {}
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group:
Ref: LogGroup
awslogs-region:
Ref: AWS::Region
awslogs-stream-prefix: cloudformation
Name: web
PortMappings:
- ContainerPort: 5000
HostPort: 5000
Protocol: tcp
RepositoryCredentials:
CredentialsParameter: arn:aws:secretsmanager:XXXXXXXXXXXXXXXXXXXXXXXX
Cpu: "256"
ExecutionRoleArn:
Ref: WebTaskExecutionRole
Family: cloudformation-web
Memory: "512"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Type: AWS::ECS::TaskDefinition
WebTaskExecutionRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Condition: {}
Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Version: 2012-10-17
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
Policies:
- PolicyDocument:
Statement:
- Action:
- secretsmanager:GetSecretValue
- ssm:GetParameters
- kms:Decrypt
Condition: {}
Effect: Allow
Principal: {}
Resource:
- arn:aws:secretsmanager:XXXXXXXXXXXXXXXXXXXXXXXX
PolicyName: webGrantAccessToSecrets
Tags:
- Key: com.docker.compose.project
Value: cloudformation
- Key: com.docker.compose.service
Value: web
Type: AWS::IAM::Role
Upvotes: 1
Views: 528
Reputation: 238051
docker compose convert
does not create valid CloudFormation (CFN) template in default context. Before you attempt to generate it, you have to create ECS context:
docker context create ecs myecscontext
Then you have to switch from default
context to myecscontext
:
docker context use myecscontext
Use docker context ls
to confirm that you are in the correct context (i.e., myecscontext
). Then you can use your convert
command
docker compose convert
to generate actual CFN template.
Upvotes: 1