Add ability to link containers in one pod
This commit is contained in:
@@ -39,6 +39,7 @@ const (
|
|||||||
// Values is kept in memory to create a values.yaml file.
|
// Values is kept in memory to create a values.yaml file.
|
||||||
var Values = make(map[string]map[string]interface{})
|
var Values = make(map[string]map[string]interface{})
|
||||||
var VolumeValues = make(map[string]map[string]map[string]interface{})
|
var VolumeValues = make(map[string]map[string]map[string]interface{})
|
||||||
|
var EmptyDirs = []string{}
|
||||||
|
|
||||||
var dependScript = `
|
var dependScript = `
|
||||||
OK=0
|
OK=0
|
||||||
@@ -51,18 +52,21 @@ echo
|
|||||||
echo "Done"
|
echo "Done"
|
||||||
`
|
`
|
||||||
|
|
||||||
|
var madeDeployments = make(map[string]helm.Deployment, 0)
|
||||||
|
|
||||||
// Create a Deployment for a given compose.Service. It returns a list of objects: a Deployment and a possible Service (kubernetes represnetation as maps).
|
// Create a Deployment for a given compose.Service. It returns a list of objects: a Deployment and a possible Service (kubernetes represnetation as maps).
|
||||||
func CreateReplicaObject(name string, s *compose.Service) chan interface{} {
|
func CreateReplicaObject(name string, s *compose.Service, linked map[string]*compose.Service) chan interface{} {
|
||||||
ret := make(chan interface{}, len(s.Ports)+len(s.Expose)+1)
|
ret := make(chan interface{}, len(s.Ports)+len(s.Expose)+1)
|
||||||
go parseService(name, s, ret)
|
go parseService(name, s, linked, ret)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will try to yied deployment and services based on a service from the compose file structure.
|
// This function will try to yied deployment and services based on a service from the compose file structure.
|
||||||
func parseService(name string, s *compose.Service, ret chan interface{}) {
|
func parseService(name string, s *compose.Service, linked map[string]*compose.Service, ret chan interface{}) {
|
||||||
Magenta(ICON_PACKAGE+" Generating deployment for ", name)
|
Magenta(ICON_PACKAGE+" Generating deployment for ", name)
|
||||||
|
|
||||||
o := helm.NewDeployment(name)
|
o := helm.NewDeployment(name)
|
||||||
|
|
||||||
container := helm.NewContainer(name, s.Image, s.Environment, s.Labels)
|
container := helm.NewContainer(name, s.Image, s.Environment, s.Labels)
|
||||||
|
|
||||||
// prepare cm and secrets
|
// prepare cm and secrets
|
||||||
@@ -83,7 +87,11 @@ func parseService(name string, s *compose.Service, ret chan interface{}) {
|
|||||||
o.Spec.Template.Spec.Containers = []*helm.Container{container}
|
o.Spec.Template.Spec.Containers = []*helm.Container{container}
|
||||||
|
|
||||||
// Prepare volumes
|
// Prepare volumes
|
||||||
o.Spec.Template.Spec.Volumes = prepareVolumes(name, s, container, ret)
|
madePVC := make(map[string]bool)
|
||||||
|
o.Spec.Template.Spec.Volumes = prepareVolumes(name, name, s, container, madePVC, ret)
|
||||||
|
|
||||||
|
// Now, for "depends_on" section, it's a bit tricky to get dependencies, see the function below.
|
||||||
|
o.Spec.Template.Spec.InitContainers = prepareInitContainers(name, s, container)
|
||||||
|
|
||||||
// Add selectors
|
// Add selectors
|
||||||
selectors := buildSelector(name, s)
|
selectors := buildSelector(name, s)
|
||||||
@@ -92,8 +100,38 @@ func parseService(name string, s *compose.Service, ret chan interface{}) {
|
|||||||
}
|
}
|
||||||
o.Spec.Template.Metadata.Labels = selectors
|
o.Spec.Template.Metadata.Labels = selectors
|
||||||
|
|
||||||
// Now, for "depends_on" section, it's a bit tricky to get dependencies, see the function below.
|
// Now, the linked services
|
||||||
o.Spec.Template.Spec.InitContainers = prepareInitContainers(name, s, container)
|
for lname, link := range linked {
|
||||||
|
container := helm.NewContainer(lname, link.Image, link.Environment, link.Labels)
|
||||||
|
container.Image = "{{ .Values." + lname + ".image }}"
|
||||||
|
Values[lname] = map[string]interface{}{
|
||||||
|
"image": link.Image,
|
||||||
|
}
|
||||||
|
prepareProbes(lname, link, container)
|
||||||
|
generateContainerPorts(link, lname, container)
|
||||||
|
o.Spec.Template.Spec.Containers = append(o.Spec.Template.Spec.Containers, container)
|
||||||
|
o.Spec.Template.Spec.Volumes = append(o.Spec.Template.Spec.Volumes, prepareVolumes(name, lname, link, container, madePVC, ret)...)
|
||||||
|
o.Spec.Template.Spec.InitContainers = append(o.Spec.Template.Spec.InitContainers, prepareInitContainers(lname, link, container)...)
|
||||||
|
//append ports and expose ports to the deployment, to be able to generate them in the Service file
|
||||||
|
if len(link.Ports) > 0 || len(link.Expose) > 0 {
|
||||||
|
s.Ports = append(s.Ports, link.Ports...)
|
||||||
|
s.Expose = append(s.Expose, link.Expose...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove duplicates in volumes
|
||||||
|
volumes := make([]map[string]interface{}, 0)
|
||||||
|
done := make(map[string]bool)
|
||||||
|
for _, vol := range o.Spec.Template.Spec.Volumes {
|
||||||
|
name := vol["name"].(string)
|
||||||
|
if _, ok := done[name]; ok {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
done[name] = true
|
||||||
|
volumes = append(volumes, vol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o.Spec.Template.Spec.Volumes = volumes
|
||||||
|
|
||||||
// Then, create Services and possible Ingresses for ingress labels, "ports" and "expose" section
|
// Then, create Services and possible Ingresses for ingress labels, "ports" and "expose" section
|
||||||
if len(s.Ports) > 0 || len(s.Expose) > 0 {
|
if len(s.Ports) > 0 || len(s.Expose) > 0 {
|
||||||
@@ -335,7 +373,7 @@ func generateContainerPorts(s *compose.Service, name string, container *helm.Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepareVolumes add the volumes of a service.
|
// prepareVolumes add the volumes of a service.
|
||||||
func prepareVolumes(name string, s *compose.Service, container *helm.Container, ret chan interface{}) []map[string]interface{} {
|
func prepareVolumes(deployment, name string, s *compose.Service, container *helm.Container, madePVC map[string]bool, ret chan interface{}) []map[string]interface{} {
|
||||||
|
|
||||||
volumes := make([]map[string]interface{}, 0)
|
volumes := make([]map[string]interface{}, 0)
|
||||||
mountPoints := make([]interface{}, 0)
|
mountPoints := make([]interface{}, 0)
|
||||||
@@ -383,11 +421,25 @@ func prepareVolumes(name string, s *compose.Service, container *helm.Container,
|
|||||||
})
|
})
|
||||||
ret <- cm
|
ret <- cm
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// rmove minus sign from volume name
|
// rmove minus sign from volume name
|
||||||
volname = strings.ReplaceAll(volname, "-", "")
|
volname = strings.ReplaceAll(volname, "-", "")
|
||||||
|
|
||||||
pvc := helm.NewPVC(name, volname)
|
isEmptyDir := false
|
||||||
|
for _, v := range EmptyDirs {
|
||||||
|
v = strings.ReplaceAll(v, "-", "")
|
||||||
|
if v == volname {
|
||||||
|
volumes = append(volumes, map[string]interface{}{
|
||||||
|
"name": volname,
|
||||||
|
"emptyDir": map[string]string{},
|
||||||
|
})
|
||||||
|
isEmptyDir = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isEmptyDir {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
volumes = append(volumes, map[string]interface{}{
|
volumes = append(volumes, map[string]interface{}{
|
||||||
"name": volname,
|
"name": volname,
|
||||||
"persistentVolumeClaim": map[string]string{
|
"persistentVolumeClaim": map[string]string{
|
||||||
@@ -399,17 +451,22 @@ func prepareVolumes(name string, s *compose.Service, container *helm.Container,
|
|||||||
"mountPath": volepath,
|
"mountPath": volepath,
|
||||||
})
|
})
|
||||||
|
|
||||||
Yellow(ICON_STORE+" Generate volume values for ", volname, " in deployment ", name)
|
Yellow(ICON_STORE+" Generate volume values", volname, "for container named", name, "in deployment", deployment)
|
||||||
locker.Lock()
|
locker.Lock()
|
||||||
if _, ok := VolumeValues[name]; !ok {
|
if _, ok := VolumeValues[deployment]; !ok {
|
||||||
VolumeValues[name] = make(map[string]map[string]interface{})
|
VolumeValues[deployment] = make(map[string]map[string]interface{})
|
||||||
}
|
}
|
||||||
VolumeValues[name][volname] = map[string]interface{}{
|
VolumeValues[deployment][volname] = map[string]interface{}{
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"capacity": "1Gi",
|
"capacity": "1Gi",
|
||||||
}
|
}
|
||||||
locker.Unlock()
|
locker.Unlock()
|
||||||
ret <- pvc
|
|
||||||
|
if _, ok := madePVC[deployment+volname]; !ok {
|
||||||
|
madePVC[deployment+volname] = true
|
||||||
|
pvc := helm.NewPVC(deployment, volname)
|
||||||
|
ret <- pvc
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.VolumeMounts = mountPoints
|
container.VolumeMounts = mountPoints
|
||||||
|
@@ -23,8 +23,39 @@ func Generate(p *compose.Parser, katernayVersion, appName, appVersion, composeFi
|
|||||||
templatesDir := filepath.Join(dirName, "templates")
|
templatesDir := filepath.Join(dirName, "templates")
|
||||||
files := make(map[string]chan interface{})
|
files := make(map[string]chan interface{})
|
||||||
|
|
||||||
|
// list avoided services
|
||||||
|
avoids := make(map[string]bool)
|
||||||
|
for n, service := range p.Data.Services {
|
||||||
|
if _, ok := service.Labels[helm.LABEL_SAMEPOD]; ok {
|
||||||
|
avoids[n] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for name, s := range p.Data.Services {
|
for name, s := range p.Data.Services {
|
||||||
files[name] = CreateReplicaObject(name, s)
|
|
||||||
|
// Manage emptyDir volumes
|
||||||
|
if empty, ok := s.Labels[helm.LABEL_EMPTYDIRS]; ok {
|
||||||
|
//split empty list by coma
|
||||||
|
emptyDirs := strings.Split(empty, ",")
|
||||||
|
//append them in EmptyDirs
|
||||||
|
EmptyDirs = append(EmptyDirs, emptyDirs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch corresponding service in "links"
|
||||||
|
linked := make(map[string]*compose.Service, 0)
|
||||||
|
// find service linked to this one
|
||||||
|
for n, service := range p.Data.Services {
|
||||||
|
if _, ok := service.Labels[helm.LABEL_SAMEPOD]; ok {
|
||||||
|
if service.Labels[helm.LABEL_SAMEPOD] == name {
|
||||||
|
linked[n] = service
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, found := avoids[name]; found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
files[name] = CreateReplicaObject(name, s, linked)
|
||||||
}
|
}
|
||||||
|
|
||||||
// to generate notes, we need to keep an Ingresses list
|
// to generate notes, we need to keep an Ingresses list
|
||||||
|
@@ -10,9 +10,12 @@ import (
|
|||||||
|
|
||||||
func BuildStorage(storage *helm.Storage, name, templatesDir string) {
|
func BuildStorage(storage *helm.Storage, name, templatesDir string) {
|
||||||
kind := "pvc"
|
kind := "pvc"
|
||||||
fname := filepath.Join(templatesDir, name+"."+kind+".yaml")
|
name = storage.Metadata.Labels[helm.K+"/component"]
|
||||||
|
pvcname := storage.Metadata.Labels[helm.K+"/pvc-name"]
|
||||||
|
fname := filepath.Join(templatesDir, name+"-"+pvcname+"."+kind+".yaml")
|
||||||
fp, _ := os.Create(fname)
|
fp, _ := os.Create(fname)
|
||||||
volname := storage.K8sBase.Metadata.Labels[helm.K+"/pvc-name"]
|
volname := storage.K8sBase.Metadata.Labels[helm.K+"/pvc-name"]
|
||||||
|
|
||||||
fp.WriteString("{{ if .Values." + name + ".persistence." + volname + ".enabled }}\n")
|
fp.WriteString("{{ if .Values." + name + ".persistence." + volname + ".enabled }}\n")
|
||||||
enc := yaml.NewEncoder(fp)
|
enc := yaml.NewEncoder(fp)
|
||||||
enc.SetIndent(IndentSize)
|
enc.SetIndent(IndentSize)
|
||||||
|
@@ -19,6 +19,8 @@ const (
|
|||||||
LABEL_ENV_SERVICE = K + "/env-to-service"
|
LABEL_ENV_SERVICE = K + "/env-to-service"
|
||||||
LABEL_VOL_CM = K + "/configmap-volumes"
|
LABEL_VOL_CM = K + "/configmap-volumes"
|
||||||
LABEL_HEALTHCHECK = K + "/healthcheck"
|
LABEL_HEALTHCHECK = K + "/healthcheck"
|
||||||
|
LABEL_SAMEPOD = K + "/same-pod"
|
||||||
|
LABEL_EMPTYDIRS = K + "/empty-dirs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetLabelsDocumentation() string {
|
func GetLabelsDocumentation() string {
|
||||||
@@ -29,6 +31,8 @@ func GetLabelsDocumentation() string {
|
|||||||
{{.LABEL_INGRESS | printf "%-33s"}}: set the port to expose in an ingress
|
{{.LABEL_INGRESS | printf "%-33s"}}: set the port to expose in an ingress
|
||||||
{{.LABEL_ENV_SERVICE | printf "%-33s"}}: specifies that the environment variable points on a service name
|
{{.LABEL_ENV_SERVICE | printf "%-33s"}}: specifies that the environment variable points on a service name
|
||||||
{{.LABEL_VOL_CM | printf "%-33s"}}: specifies that the volume points on a configmap
|
{{.LABEL_VOL_CM | printf "%-33s"}}: specifies that the volume points on a configmap
|
||||||
|
{{.LABEL_SAMEPOD | printf "%-33s}}: specifies that the pod should be deployed in the same pod than the given service name
|
||||||
|
{{.LABEL_EMPTYDIRS | printf "%-33s"}}: specifies that the volume should be "emptyDir" instead of persistentVolumeClaim
|
||||||
{{.LABEL_HEALTHCHECK | printf "%-33s"}}: specifies that the container should be monitored by a healthcheck, **it overrides the docker-compose healthcheck**.
|
{{.LABEL_HEALTHCHECK | printf "%-33s"}}: specifies that the container should be monitored by a healthcheck, **it overrides the docker-compose healthcheck**.
|
||||||
{{ printf "%-34s" ""}} You can use these form of label values:
|
{{ printf "%-34s" ""}} You can use these form of label values:
|
||||||
{{ printf "%-35s" ""}}- "http://[not used address][:port][/path]" to specify an http healthcheck
|
{{ printf "%-35s" ""}}- "http://[not used address][:port][/path]" to specify an http healthcheck
|
||||||
@@ -43,6 +47,8 @@ func GetLabelsDocumentation() string {
|
|||||||
"LABEL_INGRESS": LABEL_INGRESS,
|
"LABEL_INGRESS": LABEL_INGRESS,
|
||||||
"LABEL_VOL_CM": LABEL_VOL_CM,
|
"LABEL_VOL_CM": LABEL_VOL_CM,
|
||||||
"LABEL_HEALTHCHECK": LABEL_HEALTHCHECK,
|
"LABEL_HEALTHCHECK": LABEL_HEALTHCHECK,
|
||||||
|
"LABEL_SAMEPOD": LABEL_SAMEPOD,
|
||||||
|
"LABEL_EMPTYDIRS": LABEL_EMPTYDIRS,
|
||||||
})
|
})
|
||||||
return buff.String()
|
return buff.String()
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user