Service can freely communicate within a network

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-05-28 16:45:53 +02:00
parent 6c57fb9693
commit 5783b63556
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
6 changed files with 93 additions and 24 deletions

View File

@ -55,11 +55,9 @@ according to the networks declared in Compose model. Doing so, services attached
communicate together, while services from distinct SecurityGroups can't. We just can't set service aliasses per network.
A CloudMap private namespace is created for application as `{project}.local`. Services get registered so that we
get service discovery and DNS round-robin (equivalent for Compose's `endpoint_mode: dnsrr`). Hostname-only service
discovery is enabled by running application containers with `LOCALDOMAIN={project}.local`
(see [resolv.conf(5)](http://man7.org/linux/man-pages/man5/resolv.conf.5.html)). This works out-of-the-box for
debian-based Docker images. Alpine images have to include a tiny entrypoint script to replicate this feature:
get service discovery and DNS round-robin (equivalent for Compose's `endpoint_mode: dnsrr`). Docker images SHOULD
include a tiny entrypoint script to replicate this feature:
```shell script
if [ $LOCALDOMAIN ]; then echo "search ${LOCALDOMAIN}" >> /etc/resolv.conf; fi
if [ ! -z LOCALDOMAIN ]; then echo "search ${LOCALDOMAIN}" >> /etc/resolv.conf; fi
```

View File

@ -5,6 +5,8 @@ import (
"regexp"
"strings"
"github.com/compose-spec/compose-go/types"
"github.com/sirupsen/logrus"
cloudmapapi "github.com/aws/aws-sdk-go/service/servicediscovery"
@ -77,9 +79,10 @@ func (c client) Convert(project *compose.Project) (*cloudformation.Template, err
}
cluster := cloudformation.If("CreateCluster", cloudformation.Ref("Cluster"), cloudformation.Ref(ParameterClusterName))
for net := range project.Networks {
name, resource := convertNetwork(project, net, cloudformation.Ref(ParameterVPCId))
template.Resources[name] = resource
for _, net := range project.Networks {
for k, v := range convertNetwork(project, net, cloudformation.Ref(ParameterVPCId)) {
template.Resources[k] = v
}
}
logGroup := fmt.Sprintf("/docker-compose/%s", project.Name)
@ -204,25 +207,28 @@ func (c client) Convert(project *compose.Project) (*cloudformation.Template, err
return template, nil
}
func convertNetwork(project *compose.Project, net string, vpc string) (string, cloudformation.Resource) {
func convertNetwork(project *compose.Project, net types.NetworkConfig, vpc string) map[string]cloudformation.Resource {
resources := map[string]cloudformation.Resource{}
var ingresses []ec2.SecurityGroup_Ingress
for _, service := range project.Services {
if _, ok := service.Networks[net]; ok {
for _, port := range service.Ports {
ingresses = append(ingresses, ec2.SecurityGroup_Ingress{
CidrIp: "0.0.0.0/0",
Description: fmt.Sprintf("%s:%d/%s", service.Name, port.Target, port.Protocol),
FromPort: int(port.Target),
IpProtocol: strings.ToUpper(port.Protocol),
ToPort: int(port.Target),
})
if !net.Internal {
for _, service := range project.Services {
if _, ok := service.Networks[net.Name]; ok {
for _, port := range service.Ports {
ingresses = append(ingresses, ec2.SecurityGroup_Ingress{
CidrIp: "0.0.0.0/0",
Description: fmt.Sprintf("%s:%d/%s", service.Name, port.Target, port.Protocol),
FromPort: int(port.Target),
IpProtocol: strings.ToUpper(port.Protocol),
ToPort: int(port.Target),
})
}
}
}
}
securityGroup := networkResourceName(project, net)
resource := &ec2.SecurityGroup{
GroupDescription: fmt.Sprintf("%s %s Security Group", project.Name, net),
securityGroup := networkResourceName(project, net.Name)
resources[securityGroup] = &ec2.SecurityGroup{
GroupDescription: fmt.Sprintf("%s %s Security Group", project.Name, net.Name),
GroupName: securityGroup,
SecurityGroupIngress: ingresses,
VpcId: vpc,
@ -233,11 +239,20 @@ func convertNetwork(project *compose.Project, net string, vpc string) (string, c
},
{
Key: NetworkTag,
Value: net,
Value: net.Name,
},
},
}
return securityGroup, resource
ingress := securityGroup + "Ingress"
resources[ingress] = &ec2.SecurityGroupIngress{
Description: fmt.Sprintf("Allow communication within network %s", net.Name),
IpProtocol: "-1", // all protocols
GroupId: cloudformation.Ref(securityGroup),
SourceSecurityGroupId: cloudformation.Ref(securityGroup),
}
return resources
}
func networkResourceName(project *compose.Project, network string) string {

View File

@ -232,6 +232,19 @@
}
},
"Type": "AWS::EC2::SecurityGroup"
},
"TestSimpleConvertDefaultNetworkIngress": {
"Properties": {
"Description": "Allow communication within network default",
"GroupId": {
"Ref": "TestSimpleConvertDefaultNetwork"
},
"IpProtocol": "-1",
"SourceSecurityGroupId": {
"Ref": "TestSimpleConvertDefaultNetwork"
}
},
"Type": "AWS::EC2::SecurityGroupIngress"
}
}
}

View File

@ -232,6 +232,19 @@
}
},
"Type": "AWS::EC2::SecurityGroup"
},
"TestSimpleWithOverridesDefaultNetworkIngress": {
"Properties": {
"Description": "Allow communication within network default",
"GroupId": {
"Ref": "TestSimpleWithOverridesDefaultNetwork"
},
"IpProtocol": "-1",
"SourceSecurityGroupId": {
"Ref": "TestSimpleWithOverridesDefaultNetwork"
}
},
"Type": "AWS::EC2::SecurityGroupIngress"
}
}
}

View File

@ -54,6 +54,7 @@ func (c *client) ComposeUp(ctx context.Context, project *compose.Project) error
return err
}
fmt.Println()
return c.WaitStackCompletion(ctx, project.Name, StackCreate)
}

View File

@ -49,5 +49,34 @@ func Normalize(model *types.Config) error {
}
model.Services[i] = s
}
for i, n := range model.Networks {
if n.Name == "" {
n.Name = i
model.Networks[i] = n
}
}
for i, v := range model.Volumes {
if v.Name == "" {
v.Name = i
model.Volumes[i] = v
}
}
for i, c := range model.Configs {
if c.Name == "" {
c.Name = i
model.Configs[i] = c
}
}
for i, s := range model.Secrets {
if s.Name == "" {
s.Name = i
model.Secrets[i] = s
}
}
return nil
}