diff --git a/README.md b/README.md index 7235097..343b46f 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ No modules. | [extraEnv](#input\_extraEnv) | Extra environment variables to be added to the runner pods. | `map(string)` | `{}` | no | | [extraEnvFrom](#input\_extraEnvFrom) | Additional environment variables from other data sources (k8s secrets). |
map(object({
secretKeyRef : object({
name : string
key : string
})
}))
| `{}` | no | | [extraObjects](#input\_extraObjects) | Additional k8s objects to be created. | `list(map(any))` | `[]` | no | +| [gitlabUrl](#input\_gitlabUrl) | The GitLab Server URL (with protocol) that want to register the runner against. | `string` | n/a | yes | | [helm\_settings](#input\_helm\_settings) | The settings for the Helm chart. |
object({
name = optional(string, "gitlab-runner")
repository = optional(string, "https://charts.gitlab.io")
chart = optional(string, "gitlab-runner")
namespace = optional(string, "gitlab-runner")
version = optional(string, null) //default to last version
create_namespace = optional(bool, false)
atomic = optional(bool, true)
wait = optional(bool, true)
timeout = optional(number, 300)
})
| `{}` | no | | [hostAliases](#input\_hostAliases) | List of hosts and IPs that will be injected into the pod's hosts file. |
list(object({
ip : string
hostnames : list(string)
}))
| `[]` | no | | [hpa](#input\_hpa) | Horizontal Pod Autoscaling with API limited to metrics specification only (api/version: autoscaling/v2). |
object({
minReplicas = number
maxReplicas = number
behavior = object({
scale_up = object({
stabilizationWindowSeconds = number
selectPolicy = string
policies = list(object({
type = string
value = number
periodSeconds = number
}))
})
scaleDown = object({
stabilizationWindowSeconds = number
selectPolicy = string
policies = list(object({
type = string
value = number
period_seconds = number
}))
})
})
metrics = list(object({
type = string

resource = optional(object({
name = string
target = object({
type = string
averageUtilization = optional(number)
averageValue = optional(string)
value = optional(string)
})
}))
pods = optional(object({
metric = object({
name = string
selector = optional(object({
matchLabels = optional(map(string))
}))
})
target = object({
type = string
averageValue = optional(string)
value = optional(string)
})
}))
object = optional(object({
metric = object({
name = string
selector = optional(object({
matchLabels = optional(map(string))
}))
})
describedObject = object({
apiVersion = string
kind = string
name = string
})
target = object({
type = string
averageValue = optional(string)
value = optional(string)
})
}))
external = optional(object({
metric = object({
name = string
selector = optional(object({
matchLabels = optional(map(string))
}))
})
target = optional(object({
type = string
averageValue = optional(string)
value = optional(string)
}))
}))
containerResource = optional(object({
name = string
container = string
target = object({
type = string
averageUtilization = optional(number)
averageValue = optional(string)
value = optional(string)
})
}))
}))
})
| `null` | no | @@ -119,7 +120,7 @@ No modules. | [replicas](#input\_replicas) | The number of runner pods to create. | `number` | `1` | no | | [resources](#input\_resources) | The CPU and memory resources given to the runner. |
object({
requests = optional(object({
cpu = optional(string)
memory = optional(string)
ephemeral-storage = optional(string)
})),
limits = optional(object({
cpu = optional(string)
memory = optional(string)
ephemeral-storage = optional(string)
}))
})
| `null` | no | | [runnerToken](#input\_runnerToken) | The Runner Token for adding new Runners to the GitLab Server. | `string` | n/a | yes | -| [runners](#input\_runners) | n/a |
object({
name = string
configPath = optional(string, "") // "Absolute path for an existing runner configuration file"
secret = optional(string, null) // "Secret name containing the runner registration token"
cache = optional(map(string), {}) //Distributed cache secret
config = list(object({
executor = optional(string, "kubernetes")
shell = optional(string, "bash")
url = optional(string, "https://gitlab.com/") //TODO: values.gitlabUrl? The GitLab Server URL (with protocol) that want to register the runner against

environment = optional(list(string), null)
cache_dir = optional(string)

unhealthy_requests_limit = optional(number, 30) //The number of unhealthy responses to new job requests after which a runner worker will be disabled.
unhealthy_interval = optional(string, "120s") //Duration that a runner worker is disabled for after it exceeds the unhealthy requests limit.
output_limit = optional(number, 4096) //Maximum build log size in kilobytes. Default is 4096 (4MB).


kubernetes = object({
namespace = string
pod_labels = optional(map(string), null) // job's pods labels
pod_labels_overwrite_allowed = optional(string, null) //Regular expression to validate the contents of the pod labels overwrite environment variable. When empty, it disables the pod labels overwrite feature.
pod_annotations = optional(map(string), null) // job's annotations

poll_interval : optional(number, 3) //How frequently, in seconds, the runner will poll the Kubernetes pod it has just created to check its status
poll_timeout : optional(number, 180) //The amount of time, in seconds, that needs to pass before the runner will time out attempting to connect to the container it has just created.

image = optional(string) //The image to run jobs with.
helper_image = optional(string) //The default helper image used to clone repositories and upload artifacts.
helper_image_flavor = optional(string) //Sets the helper image flavor (alpine, alpine3.16, alpine3.17, alpine3.18, alpine3.19, alpine-latest, ubi-fips or ubuntu). Defaults to alpine. The alpine flavor uses the same version as alpine3.19.
helper_image_autoset_arch_and_os = optional(string) //Uses the underlying OS to set the Helper Image ARCH and OS.

image_pull_secrets = optional(list(string), null) // An array of items containing the Kubernetes docker-registry secret names used to authenticate Docker image pulling from private registries.
pull_policy = optional(string, "if-not-present") //The Kubernetes pull policy for the runner container. Defaults to if-not-present.
privileged = optional(bool, false) //Whether to run job's podss containers in privileged mode. Defaults to false.

// cpu requests and limits
cpu_limit : optional(string)
cpu_limit_overwrite_max_allowed : optional(string)
cpu_request : optional(string)
cpu_request_overwrite_max_allowed : optional(string)
memory_limit : optional(string)
memory_limit_overwrite_max_allowed : optional(string)
memory_request : optional(string)
memory_request_overwrite_max_allowed : optional(string)
ephemeral_storage_limit : optional(string)
ephemeral_storage_limit_overwrite_max_allowed : optional(string)
ephemeral_storage_request : optional(string)
ephemeral_storage_request_overwrite_max_allowed : optional(string)

//helper containers
helper_cpu_limit : optional(string)
helper_cpu_limit_overwrite_max_allowed : optional(string)
helper_cpu_request : optional(string)
helper_cpu_request_overwrite_max_allowed : optional(string)
helper_memory_limit : optional(string)
helper_memory_limit_overwrite_max_allowed : optional(string)
helper_memory_request : optional(string)
helper_memory_request_overwrite_max_allowed : optional(string)
helper_ephemeral_storage_limit : optional(string)
helper_ephemeral_storage_limit_overwrite_max_allowed : optional(string)
helper_ephemeral_storage_request : optional(string)
helper_ephemeral_storage_request_overwrite_max_allowed : optional(string)

// service containers
service_cpu_limit : optional(string)
service_cpu_limit_overwrite_max_allowed : optional(string)
service_cpu_request : optional(string)
service_cpu_request_overwrite_max_allowed : optional(string)
service_memory_limit : optional(string)
service_memory_limit_overwrite_max_allowed : optional(string)
service_memory_request : optional(string)
service_memory_request_overwrite_max_allowed : optional(string)
service_ephemeral_storage_limit : optional(string)
service_ephemeral_storage_limit_overwrite_max_allowed : optional(string)
service_ephemeral_storage_request : optional(string)
service_ephemeral_storage_request_overwrite_max_allowed : optional(string)

pod_security_context = optional(object({
fs_group : optional(number)
run_as_group : optional(number)
run_as_non_root : optional(bool)
run_as_user : optional(number)
supplemental_groups : optional(list(number))
selinux_options : optional(string)
}), null)

node_selector = optional(map(string), null) //Job PODs node selector
node_tolerations = optional(map(string), null) //Job PODs node tolerations

volumes = optional(object({
empty_dir = optional(list(object({
name = string
mount_path = string
medium = optional(string, null)
size_limit = optional(string, null)
})), null)
host_path = optional(list(object({
name = string
mount_path = string
host_path = string
read_only = optional(bool, false)
})), null)
pvc = optional(list(object({
name = string
mount_path = string
read_only = optional(bool, false)
})), null)
config_map = optional(list(object({
name = string
mount_path = string
read_only = optional(bool, false)
items = optional(map(string), null)
})), null)
secret = optional(list(object({
name = string
mount_path = string
read_only = optional(bool, false)
items = optional(map(string), null)
})), null)
csi = optional(list(object({
name = string
mount_path = string
read_only = optional(bool, false)
driver = string
volume_attributes = optional(map(string), null)
})), null)
}), null)

service_account = optional(string, null) //Default service account job/executor pods use to talk to Kubernetes API. If not set, the default service account is used.
service_account_overwrite_allowed = optional(string, null) //Regular expression to validate the contents of the service account overwrite environment variable. When empty, it disables the service account overwrite feature.

affinity = optional(object({
node_affinity : optional(object({
preferred_during_scheduling_ignored_during_execution : optional(list(object({
weight : number
preference : object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_fields : optional(list(object({
key : string
operator : string
values : list(string)
})))
})
})), null)
required_during_scheduling_ignored_during_execution : optional(list(object({
node_selector_terms : object({
match_expressions : optional(object({
key : string
operator : string
values : list(string)
}))
match_fields : optional(object({
key : string
operator : string
values : list(string)
}))
})
})), null)
}), null)

pod_affinity : optional(object({
preferred_during_scheduling_ignored_during_execution : optional(list(object({
pod_affinity_term : object({
weight : number
topology_key : string
namespaces : optional(list(string))
label_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
namespace_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
})
})), null)
required_during_scheduling_ignored_during_execution : optional(list(object({
topology_key : string
namespaces : optional(list(string))
label_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
namespace_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
})), null)
}), null)

pod_anti_affinity : optional(object({
preferred_during_scheduling_ignored_during_execution : optional(list(object({
pod_affinity_term : object({
weight : number
topology_key : string
namespaces : optional(list(string))
label_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
namespace_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
})
})), null)
required_during_scheduling_ignored_during_execution : optional(list(object({
topology_key : string
namespaces : optional(list(string))
label_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
namespace_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
})), null)
}), null)
}), null) //affinity
}) //kubernetes

// start of cache block
cache = optional(object({
Type = optional(string, "gcs")
Path = optional(string, "")
Shared = optional(bool)
MaxUploadedArchiveSize = optional(number)
gcs = optional(object({
CredentialsFile : optional(string)
AccessId : optional(string)
PrivateKey : optional(string)
BucketName : string
}), null)
s3 = optional(map(any), null) //TODO: add static typing as for gcs
azure = optional(map(any), null) //TODO: add static typing as for gcs
secret_name = optional(string)
}), null)
// end of cache block
})) })
| n/a | yes | +| [runners](#input\_runners) | n/a |
object({
name = string
configPath = optional(string, "") // "Absolute path for an existing runner configuration file"
secret = optional(string, null) // "Secret name containing the runner registration token"
cache = optional(map(string), {}) //Distributed cache secret
config = list(object({
executor = optional(string, "kubernetes")
shell = optional(string, "bash")

environment = optional(list(string), null)
cache_dir = optional(string)

unhealthy_requests_limit = optional(number, 30) //The number of unhealthy responses to new job requests after which a runner worker will be disabled.
unhealthy_interval = optional(string, "120s") //Duration that a runner worker is disabled for after it exceeds the unhealthy requests limit.
output_limit = optional(number, 4096) //Maximum build log size in kilobytes. Default is 4096 (4MB).


kubernetes = object({
namespace = string
pod_labels = optional(map(string), null) // job's pods labels
pod_labels_overwrite_allowed = optional(string, null) //Regular expression to validate the contents of the pod labels overwrite environment variable. When empty, it disables the pod labels overwrite feature.
pod_annotations = optional(map(string), null) // job's annotations

poll_interval : optional(number, 3) //How frequently, in seconds, the runner will poll the Kubernetes pod it has just created to check its status
poll_timeout : optional(number, 180) //The amount of time, in seconds, that needs to pass before the runner will time out attempting to connect to the container it has just created.

image = optional(string) //The image to run jobs with.
helper_image = optional(string) //The default helper image used to clone repositories and upload artifacts.
helper_image_flavor = optional(string) //Sets the helper image flavor (alpine, alpine3.16, alpine3.17, alpine3.18, alpine3.19, alpine-latest, ubi-fips or ubuntu). Defaults to alpine. The alpine flavor uses the same version as alpine3.19.
helper_image_autoset_arch_and_os = optional(string) //Uses the underlying OS to set the Helper Image ARCH and OS.

image_pull_secrets = optional(list(string), null) // An array of items containing the Kubernetes docker-registry secret names used to authenticate Docker image pulling from private registries.
pull_policy = optional(string, "if-not-present") //The Kubernetes pull policy for the runner container. Defaults to if-not-present.
privileged = optional(bool, false) //Whether to run job's podss containers in privileged mode. Defaults to false.

// cpu requests and limits
cpu_limit : optional(string)
cpu_limit_overwrite_max_allowed : optional(string)
cpu_request : optional(string)
cpu_request_overwrite_max_allowed : optional(string)
memory_limit : optional(string)
memory_limit_overwrite_max_allowed : optional(string)
memory_request : optional(string)
memory_request_overwrite_max_allowed : optional(string)
ephemeral_storage_limit : optional(string)
ephemeral_storage_limit_overwrite_max_allowed : optional(string)
ephemeral_storage_request : optional(string)
ephemeral_storage_request_overwrite_max_allowed : optional(string)

//helper containers
helper_cpu_limit : optional(string)
helper_cpu_limit_overwrite_max_allowed : optional(string)
helper_cpu_request : optional(string)
helper_cpu_request_overwrite_max_allowed : optional(string)
helper_memory_limit : optional(string)
helper_memory_limit_overwrite_max_allowed : optional(string)
helper_memory_request : optional(string)
helper_memory_request_overwrite_max_allowed : optional(string)
helper_ephemeral_storage_limit : optional(string)
helper_ephemeral_storage_limit_overwrite_max_allowed : optional(string)
helper_ephemeral_storage_request : optional(string)
helper_ephemeral_storage_request_overwrite_max_allowed : optional(string)

// service containers
service_cpu_limit : optional(string)
service_cpu_limit_overwrite_max_allowed : optional(string)
service_cpu_request : optional(string)
service_cpu_request_overwrite_max_allowed : optional(string)
service_memory_limit : optional(string)
service_memory_limit_overwrite_max_allowed : optional(string)
service_memory_request : optional(string)
service_memory_request_overwrite_max_allowed : optional(string)
service_ephemeral_storage_limit : optional(string)
service_ephemeral_storage_limit_overwrite_max_allowed : optional(string)
service_ephemeral_storage_request : optional(string)
service_ephemeral_storage_request_overwrite_max_allowed : optional(string)

pod_security_context = optional(object({
fs_group : optional(number)
run_as_group : optional(number)
run_as_non_root : optional(bool)
run_as_user : optional(number)
supplemental_groups : optional(list(number))
selinux_options : optional(string)
}), null)

node_selector = optional(map(string), null) //Job PODs node selector
node_tolerations = optional(map(string), null) //Job PODs node tolerations

volumes = optional(object({
empty_dir = optional(list(object({
name = string
mount_path = string
medium = optional(string, null)
size_limit = optional(string, null)
})), null)
host_path = optional(list(object({
name = string
mount_path = string
host_path = string
read_only = optional(bool, false)
})), null)
pvc = optional(list(object({
name = string
mount_path = string
read_only = optional(bool, false)
})), null)
config_map = optional(list(object({
name = string
mount_path = string
read_only = optional(bool, false)
items = optional(map(string), null)
})), null)
secret = optional(list(object({
name = string
mount_path = string
read_only = optional(bool, false)
items = optional(map(string), null)
})), null)
csi = optional(list(object({
name = string
mount_path = string
read_only = optional(bool, false)
driver = string
volume_attributes = optional(map(string), null)
})), null)
}), null)

service_account = optional(string, null) //Default service account job/executor pods use to talk to Kubernetes API. If not set, the default service account is used.
service_account_overwrite_allowed = optional(string, null) //Regular expression to validate the contents of the service account overwrite environment variable. When empty, it disables the service account overwrite feature.

affinity = optional(object({
node_affinity : optional(object({
preferred_during_scheduling_ignored_during_execution : optional(list(object({
weight : number
preference : object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_fields : optional(list(object({
key : string
operator : string
values : list(string)
})))
})
})), null)
required_during_scheduling_ignored_during_execution : optional(list(object({
node_selector_terms : object({
match_expressions : optional(object({
key : string
operator : string
values : list(string)
}))
match_fields : optional(object({
key : string
operator : string
values : list(string)
}))
})
})), null)
}), null)

pod_affinity : optional(object({
preferred_during_scheduling_ignored_during_execution : optional(list(object({
pod_affinity_term : object({
weight : number
topology_key : string
namespaces : optional(list(string))
label_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
namespace_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
})
})), null)
required_during_scheduling_ignored_during_execution : optional(list(object({
topology_key : string
namespaces : optional(list(string))
label_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
namespace_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
})), null)
}), null)

pod_anti_affinity : optional(object({
preferred_during_scheduling_ignored_during_execution : optional(list(object({
pod_affinity_term : object({
weight : number
topology_key : string
namespaces : optional(list(string))
label_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
namespace_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
})
})), null)
required_during_scheduling_ignored_during_execution : optional(list(object({
topology_key : string
namespaces : optional(list(string))
label_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
namespace_selector : optional(object({
match_expressions : optional(list(object({
key : string
operator : string
values : list(string)
})))
match_labels : optional(list(string))
}))
})), null)
}), null)
}), null) //affinity
}) //kubernetes

// start of cache block
cache = optional(object({
Type = optional(string, "gcs")
Path = optional(string, "")
Shared = optional(bool)
MaxUploadedArchiveSize = optional(number)
gcs = optional(object({
CredentialsFile : optional(string)
AccessId : optional(string)
PrivateKey : optional(string)
BucketName : string
}), null)
s3 = optional(map(any), null) //TODO: add static typing as for gcs
azure = optional(map(any), null) //TODO: add static typing as for gcs
secret_name = optional(string)
}), null)
// end of cache block
})) })
| n/a | yes | | [schedulerName](#input\_schedulerName) | The name of the scheduler to use. | `string` | `null` | no | | [secrets](#input\_secrets) | Secrets to be additionally mounted to the containers. |
list(object({
name = string
items = optional(list(object({
key = string
path = string
})))
}))
| `[]` | no | | [securityContext](#input\_securityContext) | Runner container security context. |
object({
allowPrivilegeEscalation : optional(bool, false)
readOnlyRootFilesystem : optional(bool, false)
runAsNonRoot : optional(bool, true)
privileged : optional(bool, false)
capabilities : optional(object({
add : optional(list(string), [])
drop : optional(list(string), [])
}), { drop : ["ALL"] })
})
| `{}` | no | diff --git a/main.tf b/main.tf index dacef35..454dbf9 100644 --- a/main.tf +++ b/main.tf @@ -19,9 +19,9 @@ locals { livenessProbe = var.livenessProbe readinessProbe = var.readinessProbe + replicas = var.replicas - replicas = var.replicas - + gitlabUrl = var.gitlabUrl runnerToken = var.runnerToken uregisterRunners = var.unregisterRunners terminationGracePeriodSeconds = var.terminationGracePeriodSeconds diff --git a/variables.tf b/variables.tf index 8ba0549..c8c842b 100644 --- a/variables.tf +++ b/variables.tf @@ -82,6 +82,11 @@ variable "readinessProbe" { default = {} } +variable "gitlabUrl" { + description = "The GitLab Server URL (with protocol) that want to register the runner against." + type = string +} + variable "replicas" { description = "The number of runner pods to create." type = number @@ -786,7 +791,6 @@ variable "runners" { config = list(object({ executor = optional(string, "kubernetes") shell = optional(string, "bash") - url = optional(string, "https://gitlab.com/") //TODO: values.gitlabUrl? The GitLab Server URL (with protocol) that want to register the runner against environment = optional(list(string), null) cache_dir = optional(string)