Module: Datadog::Core::Environment::Container
- Defined in:
- lib/datadog/core/environment/container.rb
Overview
For container environments
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- UUID_PATTERN =
'[0-9a-f]{8}[-_]?[0-9a-f]{4}[-_]?[0-9a-f]{4}[-_]?[0-9a-f]{4}[-_]?[0-9a-f]{12}'- CONTAINER_PATTERN =
'[0-9a-f]{64}'- PLATFORM_REGEX =
/(?<platform>.*?)(?:.slice)?$/.freeze
- POD_REGEX =
/(?<pod>(pod)?#{UUID_PATTERN})(?:.slice)?$/.freeze
- CONTAINER_REGEX =
/(?<container>#{UUID_PATTERN}|#{CONTAINER_PATTERN})(?:.scope)?$/.freeze
- FARGATE_14_CONTAINER_REGEX =
/(?<container>[0-9a-f]{32}-[0-9]{1,10})/.freeze
- HOST_CGROUP_NAMESPACE_INODE =
From github.com/torvalds/linux/blob/5859a2b1991101d6b978f3feb5325dad39421f29/include/linux/proc_ns.h#L41-L49 Currently, the host namespace inode number is hardcoded. We use it to determine if we’re running in the host namespace. This detection approach does not work when running in [“Docker-in-Docker”](www.docker.com/resources/docker-in-docker-containerized-ci-workflows-dockercon-2023/).
0xEFFFFFFB
Class Method Summary collapse
-
.container_id ⇒ String?
The unique identifier of the current container in the container environment.
-
.entity_id ⇒ Object
Container ID, prefixed with “ci-” or Inode, prefixed with “in-”.
-
.entry ⇒ Object
All cgroup entries have the same container identity.
-
.external_env ⇒ Object
External data supplied by the Datadog Cluster Agent Admission Controller.
-
.inode ⇒ Integer?
A unique identifier for the execution context (container or host namespace).
-
.platform ⇒ String?
The container orchestration platform or runtime environment.
-
.running_on_host? ⇒ Boolean
Checks if the current process is running on the host cgroup namespace.
-
.task_uid ⇒ String?
The unique identifier of the task or pod containing this container.
-
.to_headers ⇒ Object
Returns HTTP headers representing container information.
Class Method Details
.container_id ⇒ String?
The unique identifier of the current container in the container environment.
73 74 75 |
# File 'lib/datadog/core/environment/container.rb', line 73 def container_id entry.container_id end |
.entity_id ⇒ Object
Container ID, prefixed with “ci-” or Inode, prefixed with “in-”.
47 48 49 50 51 52 53 |
# File 'lib/datadog/core/environment/container.rb', line 47 def entity_id if container_id "ci-#{container_id}" elsif inode "in-#{inode}" end end |
.entry ⇒ Object
All cgroup entries have the same container identity. The first valid one is sufficient. v2 entries are preferred over v1.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/datadog/core/environment/container.rb', line 120 def entry return @entry if defined?(@entry) # Scan all v2 entries first, only then falling back to v1 entries. # # To do this, we {Enumerable#partition} the list between v1 and v2, # with a `true` predicate for v2 entries, making v2 first # partition returned. # # All v2 entries have the `hierarchy` set to zero. # v1 entries have a non-zero `hierarchy`. entries = Cgroup.entries.partition { |d| d.hierarchy == '0' }.flatten(1) entries.each do |entry_obj| path = entry_obj.path next unless path # To ease handling, remove the emtpy leading "", # as `path` starts with a "/". path.delete_prefix!('/') parts = path.split('/') # With not path information, we can still use the inode if parts.empty? && entry_obj.inode && !running_on_host? return @entry = Entry.new(nil, nil, nil, entry_obj.inode) end platform = parts[0][PLATFORM_REGEX, :platform] # Extract container_id and task_uid based on path structure container_id = task_uid = nil if parts.length >= 2 # Try standard container regex first if (container_id = parts[-1][CONTAINER_REGEX, :container]) # For 3+ parts, also extract task_uid if parts.length > 2 task_uid = parts[-2][POD_REGEX, :pod] || parts[1][POD_REGEX, :pod] end else # Fall back to Fargate regex container_id = parts[-1][FARGATE_14_CONTAINER_REGEX, :container] end end # container_id is a better container identifier than inode. # We MUST only populate one of them, to avoid container identification ambiguity. if container_id return @entry = Entry.new(platform, task_uid, container_id) elsif entry_obj.inode && !running_on_host? return @entry = Entry.new(platform, task_uid, nil, entry_obj.inode) end end @entry = Entry.new # Empty entry if no valid cgroup entry is found rescue => e Datadog.logger.debug( "Error while reading container entry. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}" ) @entry = Entry.new unless defined?(@entry) @entry end |
.external_env ⇒ Object
External data supplied by the Datadog Cluster Agent Admission Controller.
57 58 59 |
# File 'lib/datadog/core/environment/container.rb', line 57 def external_env Datadog.configuration.container.external_env end |
.inode ⇒ Integer?
A unique identifier for the execution context (container or host namespace).
Used as a fallback identifier when #container_id is unavailable.
93 94 95 |
# File 'lib/datadog/core/environment/container.rb', line 93 def inode entry.inode end |
.platform ⇒ String?
The container orchestration platform or runtime environment.
Examples: Docker, Kubernetes, AWS Fargate, LXC, etc.
66 67 68 |
# File 'lib/datadog/core/environment/container.rb', line 66 def platform entry.platform end |
.running_on_host? ⇒ Boolean
Checks if the current process is running on the host cgroup namespace. This indicates that the process is not running inside a container. When unsure, we return false (not running on host).
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/datadog/core/environment/container.rb', line 100 def running_on_host? return @running_on_host if defined?(@running_on_host) @running_on_host = begin if File.exist?('/proc/self/ns/cgroup') File.stat('/proc/self/ns/cgroup').ino == HOST_CGROUP_NAMESPACE_INODE else false end rescue => e Datadog.logger.debug( "Error while checking cgroup namespace. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}" ) false end end |
.task_uid ⇒ String?
The unique identifier of the task or pod containing this container.
In Kubernetes, this is the Pod UID; in AWS ECS/Fargate, the task ID. Used to identify higher-level workloads beyond this container, enabling correlation across container restarts and multi-container applications.
84 85 86 |
# File 'lib/datadog/core/environment/container.rb', line 84 def task_uid entry.task_uid end |
.to_headers ⇒ Object
Returns HTTP headers representing container information. These can used in any Datadog request that requires origin detection. This is the recommended method to call to get container information.
38 39 40 41 42 43 44 |
# File 'lib/datadog/core/environment/container.rb', line 38 def to_headers headers = {} headers["Datadog-Container-ID"] = container_id if container_id headers["Datadog-Entity-ID"] = entity_id if entity_id headers["Datadog-External-Env"] = external_env if external_env headers end |