Skip to content
This repository was archived by the owner on May 25, 2023. It is now read-only.

Commit e39f1c3

Browse files
authored
Merge pull request #195 from lightbend/wip/dns
implement YAML generation for discovery-method=akka-dns
2 parents f8b48f1 + cc51750 commit e39f1c3

File tree

25 files changed

+904
-98
lines changed

25 files changed

+904
-98
lines changed

cli/shared/src/main/scala/com/lightbend/rp/reactivecli/annotations/Annotations.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ case class Annotations(
3737
cpu: Option[Double],
3838
endpoints: Map[String, Endpoint],
3939
managementEndpointName: Option[String],
40+
remotingEndpointName: Option[String],
4041
secrets: Seq[Secret],
4142
annotations: Seq[Annotation] = Seq.empty,
4243
privileged: Boolean,
@@ -45,6 +46,18 @@ case class Annotations(
4546
modules: Set[String],
4647
akkaClusterBootstrapSystemName: Option[String]) {
4748

49+
def headlessEndpoints: Map[String, Endpoint] =
50+
endpoints filterKeys { (k: String) =>
51+
(k.some === managementEndpointName) ||
52+
(k.some === remotingEndpointName)
53+
}
54+
55+
def publicEndpoints: Map[String, Endpoint] =
56+
endpoints filterKeys { (k: String) =>
57+
!((k.some === managementEndpointName) ||
58+
(k.some === remotingEndpointName))
59+
}
60+
4861
def applicationValidation(application: Option[String]): ValidationNel[String, Option[Seq[String]]] =
4962
application match {
5063
case None =>
@@ -118,6 +131,7 @@ object Annotations extends LazyLogging {
118131
cpu = args.cpu.orElse(cpu(labels)),
119132
endpoints = endpoints(selectArrayWithIndex(labels, ns("endpoints")), applicationVersion),
120133
managementEndpointName = managementEndpointName(labels),
134+
remotingEndpointName = remotingEndpointName(labels),
121135
secrets = secrets(selectArray(labels, ns("secrets"))),
122136
annotations = annotations(selectArray(labels, ns("annotations"))),
123137
privileged = privileged(labels),
@@ -217,6 +231,10 @@ object Annotations extends LazyLogging {
217231
labels
218232
.get(ns("management-endpoint"))
219233

234+
private[annotations] def remotingEndpointName(labels: Map[String, String]): Option[String] =
235+
labels
236+
.get(ns("remoting-endpoint"))
237+
220238
private[annotations] def endpoints(endpoints: Seq[(Int, Map[String, String])], version: Option[String]): Map[String, Endpoint] =
221239
endpoints.flatMap(v => endpoint(v._2, v._1, version)).toMap
222240

cli/shared/src/main/scala/com/lightbend/rp/reactivecli/argparse/CommandArgs.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,20 @@ case object CanaryDeploymentType extends DeploymentType
6060
case object BlueGreenDeploymentType extends DeploymentType
6161
case object RollingDeploymentType extends DeploymentType
6262

63+
/**
64+
* Represents the discovery method during Akka Boostrap on Kubernetes.
65+
*/
66+
sealed trait DiscoveryMethod
67+
object DiscoveryMethod {
68+
case object KubernetesApi extends DiscoveryMethod {
69+
override def toString: String = "kubernetes-api"
70+
}
71+
case object AkkaDns extends DiscoveryMethod {
72+
override def toString = "akka-dns"
73+
}
74+
def all = Seq(AkkaDns, KubernetesApi)
75+
}
76+
6377
/**
6478
* Represents the input argument for `generate-deployment` command.
6579
*/
@@ -68,6 +82,7 @@ case class GenerateDeploymentArgs(
6882
akkaClusterJoinExisting: Boolean = false,
6983
akkaClusterSkipValidation: Boolean = false,
7084
deploymentType: DeploymentType = CanaryDeploymentType,
85+
discoveryMethod: DiscoveryMethod = DiscoveryMethod.AkkaDns,
7186
dockerImages: Seq[String] = Seq.empty,
7287
name: Option[String] = None,
7388
version: Option[String] = None,

cli/shared/src/main/scala/com/lightbend/rp/reactivecli/argparse/InputArgs.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ object InputArgs {
3737
throw new IllegalArgumentException(s"Invalid deployment type $v. Available: ${DeploymentType.All.mkString(", ")}")
3838
}
3939

40+
implicit val discoveryMethodRead: scopt.Read[DiscoveryMethod] =
41+
scopt.Read.reads {
42+
case v if v.toLowerCase == DiscoveryMethod.AkkaDns.toString => DiscoveryMethod.AkkaDns
43+
case v if v.toLowerCase == DiscoveryMethod.KubernetesApi.toString => DiscoveryMethod.KubernetesApi
44+
case v =>
45+
throw new IllegalArgumentException(s"Invalid discovery method $v. Available: ${DiscoveryMethod.all.mkString(", ")}")
46+
}
47+
4048
implicit val logLevelsRead: scopt.Read[LogLevel] =
4149
scopt.Read.reads {
4250
case v if v.toLowerCase == "error" => LogLevel.ERROR
@@ -122,6 +130,11 @@ object InputArgs {
122130
.optional()
123131
.action(GenerateDeploymentArgs.set((t, args) => args.copy(deploymentType = t))),
124132

133+
opt[DiscoveryMethod]("discovery-method")
134+
.text(s"Sets the discovery method. Default: ${DiscoveryMethod.AkkaDns}; Available: ${DiscoveryMethod.all.mkString(", ")}")
135+
.optional()
136+
.action(GenerateDeploymentArgs.set((t, args) => args.copy(discoveryMethod = t))),
137+
125138
opt[String]("env") /* note: this argument will apply for other targets */
126139
.text("Sets an environment variable. Format: NAME=value")
127140
.minOccurs(0)

cli/shared/src/main/scala/com/lightbend/rp/reactivecli/runtime/kubernetes/Deployment.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ object Deployment {
4747
noOfReplicas: Int,
4848
externalServices: Map[String, Seq[String]],
4949
deploymentType: DeploymentType,
50+
discoveryMethod: DiscoveryMethod,
5051
jsonTransform: JsonTransform,
5152
akkaClusterJoinExisting: Boolean): ValidationNel[String, Deployment] =
5253

@@ -80,6 +81,7 @@ object Deployment {
8081
RestartPolicy.Always, // The only valid RestartPolicy for Deployment
8182
externalServices,
8283
deploymentType,
84+
discoveryMethod,
8385
akkaClusterJoinExisting,
8486
applicationArgs,
8587
appName,

cli/shared/src/main/scala/com/lightbend/rp/reactivecli/runtime/kubernetes/Job.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ object Job {
4747
noOfReplicas: Int,
4848
externalServices: Map[String, Seq[String]],
4949
deploymentType: DeploymentType,
50+
discoveryMethod: DiscoveryMethod,
5051
jsonTransform: JsonTransform,
5152
akkaClusterJoinExisting: Boolean): ValidationNel[String, Job] =
5253

@@ -79,6 +80,7 @@ object Job {
7980
if (restartPolicy == RestartPolicy.Default) RestartPolicy.OnFailure else restartPolicy,
8081
externalServices,
8182
deploymentType,
83+
discoveryMethod,
8284
akkaClusterJoinExisting,
8385
applicationArgs,
8486
appName,

cli/shared/src/main/scala/com/lightbend/rp/reactivecli/runtime/kubernetes/PodTemplate.scala

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,16 @@ object PodTemplate {
5050
/**
5151
* Generates pod environment variables specific for RP applications.
5252
*/
53-
def envs(annotations: Annotations, serviceResourceName: String, noOfReplicas: Int, externalServices: Map[String, Seq[String]], akkaClusterJoinExisting: Boolean): Map[String, EnvironmentVariable] =
53+
def envs(annotations: Annotations, serviceResourceName: String, noOfReplicas: Int, externalServices: Map[String, Seq[String]], akkaClusterJoinExisting: Boolean, discoveryMethod: DiscoveryMethod): Map[String, EnvironmentVariable] =
5454
mergeEnvs(
5555
PodEnvs,
5656
appNameEnvs(annotations.appName),
5757
annotations.version.fold(Map.empty[String, EnvironmentVariable])(versionEnvs),
5858
appTypeEnvs(annotations.appType, annotations.modules),
5959
configEnvs(annotations.configResource),
6060
akkaClusterEnvs(
61+
annotations.appName,
62+
discoveryMethod,
6163
annotations.modules,
6264
annotations.namespace,
6365
serviceResourceName,
@@ -78,6 +80,8 @@ object PodTemplate {
7880
}.toMap
7981

8082
private[kubernetes] def akkaClusterEnvs(
83+
appName: Option[String],
84+
discoveryMethod: DiscoveryMethod,
8185
modules: Set[String],
8286
namespace: Option[String],
8387
serviceResourceName: String,
@@ -90,17 +94,29 @@ object PodTemplate {
9094
else
9195
Map(
9296
"RP_JAVA_OPTS" -> LiteralEnvironmentVariable(
93-
Seq(
94-
s"-Dakka.management.cluster.bootstrap.contact-point-discovery.discovery-method=kubernetes-api",
95-
s"-Dakka.management.cluster.bootstrap.contact-point-discovery.port-name=$managementEndpointName",
96-
// https://github.com/akka/akka-management/blob/v0.20.0/cluster-bootstrap/src/main/resources/reference.conf
97-
akkaClusterBootstrapSystemName match {
98-
case Some(systemName) => s"-Dakka.management.cluster.bootstrap.contact-point-discovery.effective-name=$systemName"
99-
case _ => s"-Dakka.management.cluster.bootstrap.contact-point-discovery.effective-name=$serviceResourceName"
100-
},
101-
s"-Dakka.management.cluster.bootstrap.contact-point-discovery.required-contact-point-nr=$noOfReplicas",
102-
"-Dakka.discovery.kubernetes-api.pod-label-selector=akka.lightbend.com/service-name=%s",
103-
s"${if (akkaClusterJoinExisting) "-Dakka.management.cluster.bootstrap.form-new-cluster=false" else ""}")
97+
((discoveryMethod match {
98+
case DiscoveryMethod.KubernetesApi =>
99+
List(
100+
s"-Dakka.management.cluster.bootstrap.contact-point-discovery.discovery-method=kubernetes-api",
101+
s"-Dakka.management.cluster.bootstrap.contact-point-discovery.port-name=$managementEndpointName",
102+
// https://github.com/akka/akka-management/blob/v0.20.0/cluster-bootstrap/src/main/resources/reference.conf
103+
akkaClusterBootstrapSystemName match {
104+
case Some(systemName) => s"-Dakka.management.cluster.bootstrap.contact-point-discovery.effective-name=$systemName"
105+
case _ => s"-Dakka.management.cluster.bootstrap.contact-point-discovery.effective-name=$serviceResourceName"
106+
},
107+
"-Dakka.discovery.kubernetes-api.pod-label-selector=akka.lightbend.com/service-name=%s")
108+
case DiscoveryMethod.AkkaDns =>
109+
List(
110+
s"-Dakka.management.cluster.bootstrap.contact-point-discovery.discovery-method=akka-dns",
111+
s"-Dakka.management.cluster.bootstrap.contact-point-discovery.port-name=$managementEndpointName",
112+
appName match {
113+
case Some(name) => s"-Dakka.management.cluster.bootstrap.contact-point-discovery.service-name=$name-internal"
114+
case _ => sys.error("appName was expected")
115+
})
116+
}) ++
117+
List(
118+
s"-Dakka.management.cluster.bootstrap.contact-point-discovery.required-contact-point-nr=$noOfReplicas",
119+
s"${if (akkaClusterJoinExisting) "-Dakka.management.cluster.bootstrap.form-new-cluster=false" else ""}"))
104120
.filter(_.nonEmpty)
105121
.mkString(" ")),
106122
"RP_DYN_JAVA_OPTS" -> LiteralEnvironmentVariable(
@@ -278,6 +294,7 @@ object PodTemplate {
278294
restartPolicy: RestartPolicy.Value,
279295
externalServices: Map[String, Seq[String]],
280296
deploymentType: DeploymentType,
297+
discoveryMethod: DiscoveryMethod,
281298
akkaClusterJoinExisting: Boolean,
282299
applicationArgs: Option[Seq[String]],
283300
appName: String,
@@ -372,7 +389,7 @@ object PodTemplate {
372389
"imagePullPolicy" -> imagePullPolicy.asJson,
373390
"env" -> RpEnvironmentVariables.mergeEnvs(
374391
annotations.environmentVariables ++
375-
RpEnvironmentVariables.envs(annotations, serviceResourceName, noOfReplicas, externalServices, akkaClusterJoinExisting)).asJson,
392+
RpEnvironmentVariables.envs(annotations, serviceResourceName, noOfReplicas, externalServices, akkaClusterJoinExisting, discoveryMethod)).asJson,
376393
"ports" -> annotations.endpoints.asJson,
377394
"volumeMounts" -> secretNames
378395
.map {

cli/shared/src/main/scala/com/lightbend/rp/reactivecli/runtime/kubernetes/Service.scala

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,14 @@ object Service {
5959
apiVersion: String,
6060
clusterIp: Option[String],
6161
deploymentType: DeploymentType,
62+
discoveryMethod: DiscoveryMethod,
6263
jsonTransform: JsonTransform,
6364
loadBalancerIp: Option[String],
64-
serviceType: Option[String]): ValidationNel[String, Option[Service]] =
65+
serviceType: Option[String]): ValidationNel[String, List[Service]] =
6566
(annotations.appNameValidation |@| annotations.versionValidation) { (rawAppName, version) =>
6667
// FIXME there's a bit of code duplicate in Deployment
6768
val appName = serviceName(rawAppName)
69+
val internalAppname = appName + "-internal"
6870
val appNameVersion = serviceName(s"$appName${PodTemplate.VersionSeparator}$version")
6971

7072
val selector =
@@ -74,28 +76,50 @@ object Service {
7476
case BlueGreenDeploymentType => Json("appNameVersion" -> appNameVersion.asJson)
7577
}
7678

77-
if (annotations.endpoints.isEmpty)
78-
None
79-
else
80-
Some(
81-
Service(
82-
appName,
83-
Json(
84-
"apiVersion" -> apiVersion.asJson,
85-
"kind" -> "Service".asJson,
86-
"metadata" -> Json(
87-
"labels" -> Json(
88-
"app" -> appName.asJson),
89-
"name" -> appName.asJson)
90-
.deepmerge(
91-
annotations.namespace.fold(jEmptyObject)(ns => Json("namespace" -> serviceName(ns).asJson))),
92-
"spec" -> Json(
93-
"ports" -> annotations.endpoints.asJson,
94-
"selector" -> selector)
95-
.deepmerge(clusterIp.fold(jEmptyObject)(cIp => Json("clusterIP" -> jString(cIp))))
96-
.deepmerge(serviceType.fold(jEmptyObject)(svcType => Json("type" -> jString(svcType))))
97-
.deepmerge(loadBalancerIp.fold(jEmptyObject)(lbIp => Json("loadBalancerIP" -> jString(lbIp))))),
98-
jsonTransform))
79+
def svc(endpoints: Map[String, Endpoint]) = Service(
80+
appName,
81+
Json(
82+
"apiVersion" -> apiVersion.asJson,
83+
"kind" -> "Service".asJson,
84+
"metadata" -> Json(
85+
"labels" -> Json(
86+
"app" -> appName.asJson),
87+
"name" -> appName.asJson)
88+
.deepmerge(
89+
annotations.namespace.fold(jEmptyObject)(ns => Json("namespace" -> serviceName(ns).asJson))),
90+
"spec" -> Json(
91+
"ports" -> endpoints.asJson,
92+
"selector" -> selector)
93+
.deepmerge(clusterIp.fold(jEmptyObject)(cIp => Json("clusterIP" -> jString(cIp))))
94+
.deepmerge(serviceType.fold(jEmptyObject)(svcType => Json("type" -> jString(svcType))))
95+
.deepmerge(loadBalancerIp.fold(jEmptyObject)(lbIp => Json("loadBalancerIP" -> jString(lbIp))))),
96+
jsonTransform)
97+
98+
def headlessService(endpoints: Map[String, Endpoint]) = Service(
99+
internalAppname,
100+
Json(
101+
"apiVersion" -> apiVersion.asJson,
102+
"kind" -> "Service".asJson,
103+
"metadata" -> Json(
104+
"labels" -> Json(
105+
"app" -> appName.asJson),
106+
"annotations" -> Json(
107+
"service.alpha.kubernetes.io/tolerate-unready-endpoints" -> jString("true")),
108+
"name" -> internalAppname.asJson)
109+
.deepmerge(
110+
annotations.namespace.fold(jEmptyObject)(ns => Json("namespace" -> serviceName(ns).asJson))),
111+
"spec" -> Json(
112+
"ports" -> endpoints.asJson,
113+
"selector" -> selector,
114+
"clusterIP" -> jString("None"),
115+
"publishNotReadyAddresses" -> jTrue)),
116+
jsonTransform)
117+
118+
if (annotations.endpoints.isEmpty) List()
119+
else if (discoveryMethod == DiscoveryMethod.AkkaDns) List(
120+
headlessService(annotations.headlessEndpoints),
121+
svc(annotations.publicEndpoints))
122+
else List(svc(annotations.endpoints))
99123
}
100124
}
101125

cli/shared/src/main/scala/com/lightbend/rp/reactivecli/runtime/kubernetes/package.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ package object kubernetes extends LazyLogging {
9191
kubernetesArgs.podControllerArgs.numberOfReplicas,
9292
generateDeploymentArgs.externalServices,
9393
generateDeploymentArgs.deploymentType,
94+
generateDeploymentArgs.discoveryMethod,
9495
kubernetesArgs.transformPodControllers.fold(JsonTransform.noop)(JsonTransform.jq),
9596
generateDeploymentArgs.akkaClusterJoinExisting)
9697

@@ -105,6 +106,7 @@ package object kubernetes extends LazyLogging {
105106
kubernetesArgs.podControllerArgs.numberOfReplicas,
106107
generateDeploymentArgs.externalServices,
107108
generateDeploymentArgs.deploymentType,
109+
generateDeploymentArgs.discoveryMethod,
108110
kubernetesArgs.transformPodControllers.fold(JsonTransform.noop)(JsonTransform.jq),
109111
generateDeploymentArgs.akkaClusterJoinExisting)
110112
}
@@ -114,6 +116,7 @@ package object kubernetes extends LazyLogging {
114116
serviceApiVersion,
115117
kubernetesArgs.serviceArgs.clusterIp,
116118
generateDeploymentArgs.deploymentType,
119+
generateDeploymentArgs.discoveryMethod,
117120
kubernetesArgs.transformServices.fold(JsonTransform.noop)(JsonTransform.jq),
118121
kubernetesArgs.serviceArgs.loadBalancerIp,
119122
kubernetesArgs.serviceArgs.serviceType)

cli/shared/src/test/scala/com/lightbend/rp/reactivecli/annotations/AnnotationsTest.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ object AnnotationsTest extends TestSuite {
121121
cpu = None,
122122
endpoints = Map.empty,
123123
managementEndpointName = None,
124+
remotingEndpointName = None,
124125
secrets = Seq.empty,
125126
privileged = false,
126127
environmentVariables = Map.empty,
@@ -202,6 +203,7 @@ object AnnotationsTest extends TestSuite {
202203
"ep2" -> TcpEndpoint(1, "ep2", 1234),
203204
"ep3" -> UdpEndpoint(2, "ep3", 1234)),
204205
managementEndpointName = Some("management"),
206+
remotingEndpointName = Some("remoting"),
205207
secrets = Seq.empty,
206208
annotations = Vector(
207209
Annotation("annotationKey0", "annotationValue0"),
@@ -245,6 +247,7 @@ object AnnotationsTest extends TestSuite {
245247
cpu = Some(0.5),
246248
endpoints = Map.empty,
247249
managementEndpointName = None,
250+
remotingEndpointName = None,
248251
secrets = Seq.empty,
249252
privileged = false,
250253
environmentVariables = Map(
@@ -272,6 +275,7 @@ object AnnotationsTest extends TestSuite {
272275
cpu = None,
273276
endpoints = Map.empty,
274277
managementEndpointName = None,
278+
remotingEndpointName = None,
275279
secrets = Seq.empty,
276280
privileged = false,
277281
environmentVariables = Map.empty,
@@ -295,6 +299,7 @@ object AnnotationsTest extends TestSuite {
295299
cpu = None,
296300
endpoints = Map.empty,
297301
managementEndpointName = None,
302+
remotingEndpointName = None,
298303
secrets = Seq.empty,
299304
privileged = false,
300305
environmentVariables = Map.empty,
@@ -318,6 +323,7 @@ object AnnotationsTest extends TestSuite {
318323
cpu = None,
319324
endpoints = Map.empty,
320325
managementEndpointName = None,
326+
remotingEndpointName = None,
321327
secrets = Seq.empty,
322328
privileged = false,
323329
environmentVariables = Map.empty,
@@ -347,6 +353,7 @@ object AnnotationsTest extends TestSuite {
347353
endpoints = Map(
348354
"ep2" -> TcpEndpoint(1, "ep2", 1234)),
349355
managementEndpointName = None,
356+
remotingEndpointName = None,
350357
secrets = Seq.empty,
351358
privileged = false,
352359
environmentVariables = Map.empty,
@@ -374,6 +381,7 @@ object AnnotationsTest extends TestSuite {
374381
endpoints = Map(
375382
"ep2" -> TcpEndpoint(1, "ep2", 1234)),
376383
managementEndpointName = None,
384+
remotingEndpointName = None,
377385
secrets = Seq.empty,
378386
privileged = false,
379387
environmentVariables = Map.empty,

0 commit comments

Comments
 (0)