diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap
index cc1b6688daa46..67cf7977974d7 100644
--- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap
+++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap
@@ -23,8 +23,14 @@ Object {
 }
 `;
 
+exports[`Error CLOUD_ACCOUNT_ID 1`] = `undefined`;
+
 exports[`Error CLOUD_AVAILABILITY_ZONE 1`] = `"europe-west1-c"`;
 
+exports[`Error CLOUD_INSTANCE_ID 1`] = `undefined`;
+
+exports[`Error CLOUD_INSTANCE_NAME 1`] = `undefined`;
+
 exports[`Error CLOUD_MACHINE_TYPE 1`] = `undefined`;
 
 exports[`Error CLOUD_PROVIDER 1`] = `"gcp"`;
@@ -258,8 +264,14 @@ Object {
 }
 `;
 
+exports[`Span CLOUD_ACCOUNT_ID 1`] = `undefined`;
+
 exports[`Span CLOUD_AVAILABILITY_ZONE 1`] = `"europe-west1-c"`;
 
+exports[`Span CLOUD_INSTANCE_ID 1`] = `undefined`;
+
+exports[`Span CLOUD_INSTANCE_NAME 1`] = `undefined`;
+
 exports[`Span CLOUD_MACHINE_TYPE 1`] = `undefined`;
 
 exports[`Span CLOUD_PROVIDER 1`] = `"gcp"`;
@@ -485,8 +497,14 @@ Object {
 }
 `;
 
+exports[`Transaction CLOUD_ACCOUNT_ID 1`] = `undefined`;
+
 exports[`Transaction CLOUD_AVAILABILITY_ZONE 1`] = `"europe-west1-c"`;
 
+exports[`Transaction CLOUD_INSTANCE_ID 1`] = `undefined`;
+
+exports[`Transaction CLOUD_INSTANCE_NAME 1`] = `undefined`;
+
 exports[`Transaction CLOUD_MACHINE_TYPE 1`] = `undefined`;
 
 exports[`Transaction CLOUD_PROVIDER 1`] = `"gcp"`;
diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts
index ffd05b281208d..4b77a88e54007 100644
--- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts
+++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts
@@ -10,6 +10,9 @@ export const CLOUD_AVAILABILITY_ZONE = 'cloud.availability_zone';
 export const CLOUD_PROVIDER = 'cloud.provider';
 export const CLOUD_REGION = 'cloud.region';
 export const CLOUD_MACHINE_TYPE = 'cloud.machine.type';
+export const CLOUD_ACCOUNT_ID = 'cloud.account.id';
+export const CLOUD_INSTANCE_ID = 'cloud.instance.id';
+export const CLOUD_INSTANCE_NAME = 'cloud.instance.name';
 
 export const SERVICE = 'service';
 export const SERVICE_NAME = 'service.name';
diff --git a/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.tsx b/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.tsx
index 7dde7ed3d145d..f7bed4e09a696 100644
--- a/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.tsx
@@ -30,13 +30,13 @@ const cloudIcons: Record<string, string> = {
   azure: 'logoAzure',
 };
 
-function getCloudIcon(provider?: string) {
+export function getCloudIcon(provider?: string) {
   if (provider) {
     return cloudIcons[provider];
   }
 }
 
-function getContainerIcon(container?: ContainerType) {
+export function getContainerIcon(container?: ContainerType) {
   if (!container) {
     return;
   }
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx
index 78c8f151b82d9..cd1ced1830123 100644
--- a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx
@@ -119,7 +119,7 @@ export function ServiceOverview({
             {!isRumAgent && (
               <EuiFlexItem>
                 <EuiFlexGroup
-                  direction={rowDirection}
+                  direction="column"
                   gutterSize="s"
                   responsive={false}
                 >
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/get_columns.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/get_columns.tsx
index f52c2b083330f..4da5ba5a4ae64 100644
--- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/get_columns.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/get_columns.tsx
@@ -5,11 +5,16 @@
  * 2.0.
  */
 
-import { EuiBasicTableColumn } from '@elastic/eui';
+import {
+  EuiBasicTableColumn,
+  EuiButtonIcon,
+  RIGHT_ALIGNMENT,
+} from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
-import React from 'react';
-import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types';
+import React, { ReactNode } from 'react';
+import { ActionMenu } from '../../../../../../observability/public';
 import { isJavaAgentName } from '../../../../../common/agent_name';
+import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types';
 import {
   getServiceNodeName,
   SERVICE_NODE_NAME_MISSING,
@@ -26,6 +31,7 @@ import { MetricOverviewLink } from '../../../shared/Links/apm/MetricOverviewLink
 import { ServiceNodeMetricOverviewLink } from '../../../shared/Links/apm/ServiceNodeMetricOverviewLink';
 import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip';
 import { getLatencyColumnLabel } from '../get_latency_column_label';
+import { InstanceActionsMenu } from './instance_actions_menu';
 import { MainStatsServiceInstanceItem } from '../service_overview_instances_chart_and_table';
 
 type ServiceInstanceDetailedStatistics = APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>;
@@ -36,12 +42,20 @@ export function getColumns({
   latencyAggregationType,
   detailedStatsData,
   comparisonEnabled,
+  toggleRowDetails,
+  itemIdToExpandedRowMap,
+  toggleRowActionMenu,
+  itemIdToOpenActionMenuRowMap,
 }: {
   serviceName: string;
   agentName?: string;
   latencyAggregationType?: LatencyAggregationType;
   detailedStatsData?: ServiceInstanceDetailedStatistics;
   comparisonEnabled?: boolean;
+  toggleRowDetails: (selectedServiceNodeName: string) => void;
+  itemIdToExpandedRowMap: Record<string, ReactNode>;
+  toggleRowActionMenu: (selectedServiceNodeName: string) => void;
+  itemIdToOpenActionMenuRowMap: Record<string, boolean>;
 }): Array<EuiBasicTableColumn<MainStatsServiceInstanceItem>> {
   return [
     {
@@ -82,7 +96,7 @@ export function getColumns({
       sortable: true,
     },
     {
-      field: 'latencyValue',
+      field: 'latency',
       name: getLatencyColumnLabel(latencyAggregationType),
       width: px(unit * 10),
       render: (_, { serviceNodeName, latency }) => {
@@ -104,7 +118,7 @@ export function getColumns({
       sortable: true,
     },
     {
-      field: 'throughputValue',
+      field: 'throughput',
       name: i18n.translate(
         'xpack.apm.serviceOverview.instancesTableColumnThroughput',
         { defaultMessage: 'Throughput' }
@@ -130,7 +144,7 @@ export function getColumns({
       sortable: true,
     },
     {
-      field: 'errorRateValue',
+      field: 'errorRate',
       name: i18n.translate(
         'xpack.apm.serviceOverview.instancesTableColumnErrorRate',
         { defaultMessage: 'Error rate' }
@@ -156,7 +170,7 @@ export function getColumns({
       sortable: true,
     },
     {
-      field: 'cpuUsageValue',
+      field: 'cpuUsage',
       name: i18n.translate(
         'xpack.apm.serviceOverview.instancesTableColumnCpuUsage',
         { defaultMessage: 'CPU usage (avg.)' }
@@ -182,7 +196,7 @@ export function getColumns({
       sortable: true,
     },
     {
-      field: 'memoryUsageValue',
+      field: 'memoryUsage',
       name: i18n.translate(
         'xpack.apm.serviceOverview.instancesTableColumnMemoryUsage',
         { defaultMessage: 'Memory usage (avg.)' }
@@ -207,5 +221,56 @@ export function getColumns({
       },
       sortable: true,
     },
+    {
+      width: '40px',
+      render: (instanceItem: MainStatsServiceInstanceItem) => {
+        return (
+          <ActionMenu
+            id="instanceActionMenu"
+            closePopover={() =>
+              toggleRowActionMenu(instanceItem.serviceNodeName)
+            }
+            isOpen={itemIdToOpenActionMenuRowMap[instanceItem.serviceNodeName]}
+            anchorPosition="leftCenter"
+            button={
+              <EuiButtonIcon
+                iconType="boxesHorizontal"
+                onClick={() =>
+                  toggleRowActionMenu(instanceItem.serviceNodeName)
+                }
+              />
+            }
+          >
+            <InstanceActionsMenu
+              serviceName={serviceName}
+              serviceNodeName={instanceItem.serviceNodeName}
+              onClose={() => toggleRowActionMenu(instanceItem.serviceNodeName)}
+            />
+          </ActionMenu>
+        );
+      },
+    },
+    {
+      align: RIGHT_ALIGNMENT,
+      width: '40px',
+      isExpander: true,
+      render: (instanceItem: MainStatsServiceInstanceItem) => {
+        return (
+          <EuiButtonIcon
+            onClick={() => toggleRowDetails(instanceItem.serviceNodeName)}
+            aria-label={
+              itemIdToExpandedRowMap[instanceItem.serviceNodeName]
+                ? 'Collapse'
+                : 'Expand'
+            }
+            iconType={
+              itemIdToExpandedRowMap[instanceItem.serviceNodeName]
+                ? 'arrowUp'
+                : 'arrowDown'
+            }
+          />
+        );
+      },
+    },
   ];
 }
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx
index 1bab5e45bcc52..fe367896c4652 100644
--- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx
@@ -12,7 +12,7 @@ import {
   EuiTitle,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
-import React from 'react';
+import React, { ReactNode, useEffect, useState } from 'react';
 import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
 import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
 import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
@@ -26,6 +26,7 @@ import {
 } from '../service_overview_instances_chart_and_table';
 import { ServiceOverviewTableContainer } from '../service_overview_table_container';
 import { getColumns } from './get_columns';
+import { InstanceDetails } from './intance_details';
 
 type ServiceInstanceDetailedStatistics = APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>;
 
@@ -65,15 +66,58 @@ export function ServiceOverviewInstancesTable({
     urlParams: { latencyAggregationType, comparisonEnabled },
   } = useUrlParams();
 
+  const [
+    itemIdToOpenActionMenuRowMap,
+    setItemIdToOpenActionMenuRowMap,
+  ] = useState<Record<string, boolean>>({});
+
+  const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<
+    Record<string, ReactNode>
+  >({});
+
+  useEffect(() => {
+    // Closes any open rows when fetching new items
+    setItemIdToExpandedRowMap({});
+  }, [status]);
+
   const { pageIndex, sort } = tableOptions;
   const { direction, field } = sort;
 
+  const toggleRowActionMenu = (selectedServiceNodeName: string) => {
+    const actionMenuRowMapValues = { ...itemIdToOpenActionMenuRowMap };
+    if (actionMenuRowMapValues[selectedServiceNodeName]) {
+      delete actionMenuRowMapValues[selectedServiceNodeName];
+    } else {
+      actionMenuRowMapValues[selectedServiceNodeName] = true;
+    }
+    setItemIdToOpenActionMenuRowMap(actionMenuRowMapValues);
+  };
+
+  const toggleRowDetails = (selectedServiceNodeName: string) => {
+    const expandedRowMapValues = { ...itemIdToExpandedRowMap };
+    if (expandedRowMapValues[selectedServiceNodeName]) {
+      delete expandedRowMapValues[selectedServiceNodeName];
+    } else {
+      expandedRowMapValues[selectedServiceNodeName] = (
+        <InstanceDetails
+          serviceNodeName={selectedServiceNodeName}
+          serviceName={serviceName}
+        />
+      );
+    }
+    setItemIdToExpandedRowMap(expandedRowMapValues);
+  };
+
   const columns = getColumns({
     agentName,
     serviceName,
     latencyAggregationType,
     detailedStatsData,
     comparisonEnabled,
+    toggleRowDetails,
+    itemIdToExpandedRowMap,
+    toggleRowActionMenu,
+    itemIdToOpenActionMenuRowMap,
   });
 
   const pagination = {
@@ -106,6 +150,8 @@ export function ServiceOverviewInstancesTable({
               pagination={pagination}
               sorting={{ sort: { field, direction } }}
               onChange={onChangeTableOptions}
+              itemId="serviceNodeName"
+              itemIdToExpandedRowMap={itemIdToExpandedRowMap}
             />
           </ServiceOverviewTableContainer>
         </TableFetchWrapper>
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx
new file mode 100644
index 0000000000000..f03c2b2fc9091
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx
@@ -0,0 +1,131 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import { EuiLoadingSpinner } from '@elastic/eui';
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import {
+  ActionMenuDivider,
+  Section,
+  SectionLink,
+  SectionLinks,
+  SectionSubtitle,
+  SectionTitle,
+} from '../../../../../../../observability/public';
+import { isJavaAgentName } from '../../../../../../common/agent_name';
+import { SERVICE_NODE_NAME } from '../../../../../../common/elasticsearch_fieldnames';
+import { useApmPluginContext } from '../../../../../context/apm_plugin/use_apm_plugin_context';
+import { useUrlParams } from '../../../../../context/url_params_context/use_url_params';
+import { FETCH_STATUS } from '../../../../../hooks/use_fetcher';
+import { px } from '../../../../../style/variables';
+import { pushNewItemToKueryBar } from '../../../../shared/KueryBar/utils';
+import { useMetricOverviewHref } from '../../../../shared/Links/apm/MetricOverviewLink';
+import { useServiceNodeMetricOverviewHref } from '../../../../shared/Links/apm/ServiceNodeMetricOverviewLink';
+import { useInstanceDetailsFetcher } from '../use_instance_details_fetcher';
+import { getMenuSections } from './menu_sections';
+
+interface Props {
+  serviceName: string;
+  serviceNodeName: string;
+  onClose: () => void;
+}
+
+const POPOVER_WIDTH = px(305);
+
+export function InstanceActionsMenu({
+  serviceName,
+  serviceNodeName,
+  onClose,
+}: Props) {
+  const { core } = useApmPluginContext();
+  const { data, status } = useInstanceDetailsFetcher({
+    serviceName,
+    serviceNodeName,
+  });
+  const serviceNodeMetricOverviewHref = useServiceNodeMetricOverviewHref({
+    serviceName,
+    serviceNodeName,
+  });
+  const metricOverviewHref = useMetricOverviewHref(serviceName);
+  const history = useHistory();
+  const {
+    urlParams: { kuery },
+  } = useUrlParams();
+
+  if (
+    status === FETCH_STATUS.LOADING ||
+    status === FETCH_STATUS.NOT_INITIATED
+  ) {
+    return (
+      <div
+        style={{
+          width: POPOVER_WIDTH,
+          display: 'flex',
+          justifyContent: 'center',
+        }}
+      >
+        <EuiLoadingSpinner />
+      </div>
+    );
+  }
+
+  if (!data) {
+    return null;
+  }
+
+  const handleFilterByInstanceClick = () => {
+    onClose();
+    pushNewItemToKueryBar({
+      kuery,
+      history,
+      key: SERVICE_NODE_NAME,
+      value: serviceNodeName,
+    });
+  };
+
+  const metricsHref = isJavaAgentName(data.agent?.name)
+    ? serviceNodeMetricOverviewHref
+    : metricOverviewHref;
+
+  const sections = getMenuSections({
+    instanceDetails: data,
+    basePath: core.http.basePath,
+    onFilterByInstanceClick: handleFilterByInstanceClick,
+    metricsHref,
+  });
+
+  return (
+    <div style={{ width: POPOVER_WIDTH }}>
+      {sections.map((section, idx) => {
+        const isLastSection = idx !== sections.length - 1;
+        return (
+          <div key={idx}>
+            {section.map((item) => (
+              <Section key={item.key}>
+                {item.title && <SectionTitle>{item.title}</SectionTitle>}
+                {item.subtitle && (
+                  <SectionSubtitle>{item.subtitle}</SectionSubtitle>
+                )}
+                <SectionLinks>
+                  {item.actions.map((action) => (
+                    <SectionLink
+                      key={action.key}
+                      label={action.label}
+                      href={action.href}
+                      onClick={action.onClick}
+                      color="primary"
+                    />
+                  ))}
+                </SectionLinks>
+              </Section>
+            ))}
+            {isLastSection && <ActionMenuDivider />}
+          </div>
+        );
+      })}
+    </div>
+  );
+}
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts
new file mode 100644
index 0000000000000..30995fbd13397
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts
@@ -0,0 +1,203 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { i18n } from '@kbn/i18n';
+import { IBasePath } from 'kibana/public';
+import { isEmpty } from 'lodash';
+import moment from 'moment';
+import { APIReturnType } from '../../../../../services/rest/createCallApmApi';
+import { getInfraHref } from '../../../../shared/Links/InfraLink';
+
+type InstaceDetails = APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>;
+
+interface Action {
+  key: string;
+  label: string;
+  href?: string;
+  onClick?: () => void;
+  condition: boolean;
+}
+
+interface Section {
+  key: string;
+  title?: string;
+  subtitle?: string;
+  actions: Action[];
+}
+
+type SectionRecord = Record<string, Section[]>;
+
+function getInfraMetricsQuery(timestamp?: string) {
+  if (!timestamp) {
+    return { from: 0, to: 0 };
+  }
+  const timeInMilliseconds = new Date(timestamp).getTime();
+  const fiveMinutes = moment.duration(5, 'minutes').asMilliseconds();
+
+  return {
+    from: timeInMilliseconds - fiveMinutes,
+    to: timeInMilliseconds + fiveMinutes,
+  };
+}
+
+export function getMenuSections({
+  instanceDetails,
+  basePath,
+  onFilterByInstanceClick,
+  metricsHref,
+}: {
+  instanceDetails: InstaceDetails;
+  basePath: IBasePath;
+  onFilterByInstanceClick: () => void;
+  metricsHref: string;
+}) {
+  const podId = instanceDetails.kubernetes?.pod?.uid;
+  const containerId = instanceDetails.container?.id;
+  const time = instanceDetails['@timestamp']
+    ? new Date(instanceDetails['@timestamp']).valueOf()
+    : undefined;
+  const infraMetricsQuery = getInfraMetricsQuery(instanceDetails['@timestamp']);
+
+  const podActions: Action[] = [
+    {
+      key: 'podLogs',
+      label: i18n.translate(
+        'xpack.apm.serviceOverview.instancesTable.actionMenus.podLogs',
+        { defaultMessage: 'Pod logs' }
+      ),
+      href: getInfraHref({
+        app: 'logs',
+        basePath,
+        path: `/link-to/pod-logs/${podId}`,
+        query: { time },
+      }),
+      condition: !!podId,
+    },
+    {
+      key: 'podMetrics',
+      label: i18n.translate(
+        'xpack.apm.serviceOverview.instancesTable.actionMenus.podMetrics',
+        { defaultMessage: 'Pod metrics' }
+      ),
+      href: getInfraHref({
+        app: 'metrics',
+        basePath,
+        path: `/link-to/pod-detail/${podId}`,
+        query: infraMetricsQuery,
+      }),
+      condition: !!podId,
+    },
+  ];
+
+  const containerActions: Action[] = [
+    {
+      key: 'containerLogs',
+      label: i18n.translate(
+        'xpack.apm.serviceOverview.instancesTable.actionMenus.containerLogs',
+        { defaultMessage: 'Container logs' }
+      ),
+      href: getInfraHref({
+        app: 'logs',
+        basePath,
+        path: `/link-to/container-logs/${containerId}`,
+        query: { time },
+      }),
+      condition: !!containerId,
+    },
+    {
+      key: 'containerMetrics',
+      label: i18n.translate(
+        'xpack.apm.serviceOverview.instancesTable.actionMenus.containerMetrics',
+        { defaultMessage: 'Container metrics' }
+      ),
+      href: getInfraHref({
+        app: 'metrics',
+        basePath,
+        path: `/link-to/container-detail/${containerId}`,
+        query: infraMetricsQuery,
+      }),
+      condition: !!containerId,
+    },
+  ];
+
+  const apmActions: Action[] = [
+    {
+      key: 'filterByInstance',
+      label: i18n.translate(
+        'xpack.apm.serviceOverview.instancesTable.actionMenus.filterByInstance',
+        {
+          defaultMessage: 'Filter overview by instance',
+        }
+      ),
+      onClick: onFilterByInstanceClick,
+      condition: true,
+    },
+    {
+      key: 'analyzeRuntimeMetric',
+      label: i18n.translate(
+        'xpack.apm.serviceOverview.instancesTable.actionMenus.metrics',
+        {
+          defaultMessage: 'Metrics',
+        }
+      ),
+      href: metricsHref,
+      condition: true,
+    },
+  ];
+
+  const sectionRecord: SectionRecord = {
+    observability: [
+      {
+        key: 'podDetails',
+        title: i18n.translate(
+          'xpack.apm.serviceOverview.instancesTable.actionMenus.pod.title',
+          {
+            defaultMessage: 'Pod details',
+          }
+        ),
+        subtitle: i18n.translate(
+          'xpack.apm.serviceOverview.instancesTable.actionMenus.pod.subtitle',
+          {
+            defaultMessage:
+              'View logs and metrics for this pod to get further details.',
+          }
+        ),
+        actions: podActions,
+      },
+      {
+        key: 'containerDetails',
+        title: i18n.translate(
+          'xpack.apm.serviceOverview.instancesTable.actionMenus.container.title',
+          {
+            defaultMessage: 'Container details',
+          }
+        ),
+        subtitle: i18n.translate(
+          'xpack.apm.serviceOverview.instancesTable.actionMenus.container.subtitle',
+          {
+            defaultMessage:
+              'View logs and metrics for this container to get further details.',
+          }
+        ),
+        actions: containerActions,
+      },
+    ],
+    apm: [{ key: 'apm', actions: apmActions }],
+  };
+
+  // Filter out actions that shouldnt be shown and sections without any actions.
+  return Object.values(sectionRecord)
+    .map((sections) =>
+      sections
+        .map((section) => ({
+          ...section,
+          actions: section.actions.filter((action) => action.condition),
+        }))
+        .filter((section) => !isEmpty(section.actions))
+    )
+    .filter((sections) => !isEmpty(sections));
+}
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx
new file mode 100644
index 0000000000000..f50d02bb15454
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx
@@ -0,0 +1,144 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { EuiFlexGroup, EuiFlexItem, EuiLoadingContent } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { get } from 'lodash';
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import {
+  CLOUD_AVAILABILITY_ZONE,
+  CLOUD_INSTANCE_ID,
+  CLOUD_INSTANCE_NAME,
+  CLOUD_MACHINE_TYPE,
+  CLOUD_PROVIDER,
+  CONTAINER_ID,
+  HOST_NAME,
+  POD_NAME,
+  SERVICE_NODE_NAME,
+  SERVICE_RUNTIME_NAME,
+  SERVICE_RUNTIME_VERSION,
+  SERVICE_VERSION,
+} from '../../../../../common/elasticsearch_fieldnames';
+import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
+import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
+import { useTheme } from '../../../../hooks/use_theme';
+import { APIReturnType } from '../../../../services/rest/createCallApmApi';
+import { pct } from '../../../../style/variables';
+import { getAgentIcon } from '../../../shared/AgentIcon/get_agent_icon';
+import { KeyValueFilterList } from '../../../shared/key_value_filter_list';
+import { pushNewItemToKueryBar } from '../../../shared/KueryBar/utils';
+import {
+  getCloudIcon,
+  getContainerIcon,
+} from '../../service_details/service_icons';
+import { useInstanceDetailsFetcher } from './use_instance_details_fetcher';
+
+type ServiceInstanceDetails = APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>;
+
+interface Props {
+  serviceName: string;
+  serviceNodeName: string;
+}
+
+function toKeyValuePairs(keys: string[], data: ServiceInstanceDetails) {
+  return keys.map((key) => ({ key, value: get(data, key) }));
+}
+
+const serviceDetailsKeys = [
+  SERVICE_NODE_NAME,
+  SERVICE_VERSION,
+  SERVICE_RUNTIME_NAME,
+  SERVICE_RUNTIME_VERSION,
+];
+const containerDetailsKeys = [CONTAINER_ID, HOST_NAME, POD_NAME];
+const cloudDetailsKeys = [
+  CLOUD_AVAILABILITY_ZONE,
+  CLOUD_INSTANCE_ID,
+  CLOUD_INSTANCE_NAME,
+  CLOUD_MACHINE_TYPE,
+  CLOUD_PROVIDER,
+];
+
+export function InstanceDetails({ serviceName, serviceNodeName }: Props) {
+  const theme = useTheme();
+  const history = useHistory();
+  const {
+    urlParams: { kuery },
+  } = useUrlParams();
+
+  const { data, status } = useInstanceDetailsFetcher({
+    serviceName,
+    serviceNodeName,
+  });
+
+  if (
+    status === FETCH_STATUS.LOADING ||
+    status === FETCH_STATUS.NOT_INITIATED
+  ) {
+    return (
+      <div style={{ width: pct(50) }}>
+        <EuiLoadingContent />
+      </div>
+    );
+  }
+
+  if (!data) {
+    return null;
+  }
+
+  const addKueryBarFilter = ({ key, value }: { key: string; value: any }) => {
+    pushNewItemToKueryBar({ kuery, history, key, value });
+  };
+
+  const serviceDetailsKeyValuePairs = toKeyValuePairs(serviceDetailsKeys, data);
+  const containerDetailsKeyValuePairs = toKeyValuePairs(
+    containerDetailsKeys,
+    data
+  );
+  const cloudDetailsKeyValuePairs = toKeyValuePairs(cloudDetailsKeys, data);
+
+  const containerType = data.kubernetes?.pod?.name ? 'Kubernetes' : 'Docker';
+  return (
+    <EuiFlexGroup direction="column" responsive={false}>
+      <EuiFlexItem>
+        <KeyValueFilterList
+          initialIsOpen
+          title={i18n.translate(
+            'xpack.apm.serviceOverview.instanceTable.details.serviceTitle',
+            { defaultMessage: 'Service' }
+          )}
+          icon={getAgentIcon(data.agent?.name, theme.darkMode)}
+          keyValueList={serviceDetailsKeyValuePairs}
+          onClickFilter={addKueryBarFilter}
+        />
+      </EuiFlexItem>
+      <EuiFlexItem>
+        <KeyValueFilterList
+          title={i18n.translate(
+            'xpack.apm.serviceOverview.instanceTable.details.containerTitle',
+            { defaultMessage: 'Container' }
+          )}
+          icon={getContainerIcon(containerType)}
+          keyValueList={containerDetailsKeyValuePairs}
+          onClickFilter={addKueryBarFilter}
+        />
+      </EuiFlexItem>
+      <EuiFlexItem>
+        <KeyValueFilterList
+          title={i18n.translate(
+            'xpack.apm.serviceOverview.instanceTable.details.cloudTitle',
+            { defaultMessage: 'Cloud' }
+          )}
+          icon={getCloudIcon(data.cloud?.provider)}
+          keyValueList={cloudDetailsKeyValuePairs}
+          onClickFilter={addKueryBarFilter}
+        />
+      </EuiFlexItem>
+    </EuiFlexGroup>
+  );
+}
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/use_instance_details_fetcher.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/use_instance_details_fetcher.tsx
new file mode 100644
index 0000000000000..7a5da7e3e462b
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/use_instance_details_fetcher.tsx
@@ -0,0 +1,52 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
+import { useFetcher } from '../../../../hooks/use_fetcher';
+import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
+
+export function useInstanceDetailsFetcher({
+  serviceName,
+  serviceNodeName,
+}: {
+  serviceName: string;
+  serviceNodeName: string;
+}) {
+  const {
+    urlParams: { start, end, kuery, environment },
+  } = useUrlParams();
+  const { transactionType } = useApmServiceContext();
+
+  const { data, status } = useFetcher(
+    (callApmApi) => {
+      if (!start || !end || !transactionType) {
+        return;
+      }
+      return callApmApi({
+        endpoint:
+          'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}',
+        params: {
+          path: {
+            serviceName,
+            serviceNodeName,
+          },
+          query: { start, end, transactionType, environment, kuery },
+        },
+      });
+    },
+    [
+      serviceName,
+      serviceNodeName,
+      start,
+      end,
+      transactionType,
+      environment,
+      kuery,
+    ]
+  );
+
+  return { data, status };
+}
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_table_container.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_table_container.tsx
index 738ff0d7c735f..64b6943e73260 100644
--- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_table_container.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_table_container.tsx
@@ -32,7 +32,7 @@ const ServiceOverviewTableContainerDiv = euiStyled.div<{
     shouldUseMobileLayout
       ? ''
       : `
-  height: ${tableHeight}px;
+  min-height: ${tableHeight}px;
   display: flex;
   flex-direction: column;
 
diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/utils.ts b/x-pack/plugins/apm/public/components/shared/KueryBar/utils.ts
new file mode 100644
index 0000000000000..56aed1227b1e0
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/shared/KueryBar/utils.ts
@@ -0,0 +1,28 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { History } from 'history';
+import { isEmpty } from 'lodash';
+import { push } from '../Links/url_helpers';
+
+export function pushNewItemToKueryBar({
+  kuery,
+  history,
+  key,
+  value,
+}: {
+  kuery?: string;
+  history: History;
+  key: string;
+  value: any;
+}) {
+  const newItem = `${key} :"${value}"`;
+  const nextKuery = isEmpty(kuery) ? newItem : `${kuery} and ${newItem}`;
+  push(history, {
+    query: { kuery: encodeURIComponent(nextKuery) },
+  });
+}
diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx
index 7ad7f18b425cd..aad5756b70e7e 100644
--- a/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx
+++ b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx
@@ -5,40 +5,46 @@
  * 2.0.
  */
 
+import { EuiLink } from '@elastic/eui';
 import React from 'react';
-import { APMLink, APMLinkExtendProps } from './APMLink';
-import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
-import { pickKeys } from '../../../../../common/utils/pick_keys';
+import { APMQueryParams } from '../url_helpers';
+import { APMLinkExtendProps, useAPMHref } from './APMLink';
 
 interface Props extends APMLinkExtendProps {
   serviceName: string;
   serviceNodeName: string;
 }
 
-function ServiceNodeMetricOverviewLink({
+const persistedFilters: Array<keyof APMQueryParams> = [
+  'host',
+  'containerId',
+  'podName',
+  'serviceVersion',
+];
+
+export function useServiceNodeMetricOverviewHref({
+  serviceName,
+  serviceNodeName,
+}: {
+  serviceName: string;
+  serviceNodeName: string;
+}) {
+  return useAPMHref({
+    path: `/services/${serviceName}/nodes/${encodeURIComponent(
+      serviceNodeName
+    )}/metrics`,
+    persistedFilters,
+  });
+}
+
+export function ServiceNodeMetricOverviewLink({
   serviceName,
   serviceNodeName,
   ...rest
 }: Props) {
-  const { urlParams } = useUrlParams();
-
-  const persistedFilters = pickKeys(
-    urlParams,
-    'host',
-    'containerId',
-    'podName',
-    'serviceVersion'
-  );
-
-  return (
-    <APMLink
-      path={`/services/${serviceName}/nodes/${encodeURIComponent(
-        serviceNodeName
-      )}/metrics`}
-      query={persistedFilters}
-      {...rest}
-    />
-  );
+  const href = useServiceNodeMetricOverviewHref({
+    serviceName,
+    serviceNodeName,
+  });
+  return <EuiLink href={href} {...rest} />;
 }
-
-export { ServiceNodeMetricOverviewLink };
diff --git a/x-pack/plugins/apm/public/components/shared/key_value_filter_list/index.tsx b/x-pack/plugins/apm/public/components/shared/key_value_filter_list/index.tsx
new file mode 100644
index 0000000000000..c836919a8a6ab
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/shared/key_value_filter_list/index.tsx
@@ -0,0 +1,147 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import {
+  EuiAccordion,
+  EuiButtonEmpty,
+  EuiDescriptionList,
+  EuiDescriptionListDescription,
+  EuiDescriptionListTitle,
+  EuiFlexGroup,
+  EuiFlexItem,
+  EuiIcon,
+  EuiText,
+  EuiToolTip,
+} from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import React, { Fragment } from 'react';
+import styled from 'styled-components';
+import { px, units } from '../../../style/variables';
+
+interface KeyValue {
+  key: string;
+  value: any | undefined;
+}
+
+const StyledEuiAccordion = styled(EuiAccordion)`
+  width: 100%;
+  .buttonContentContainer .euiIEFlexWrapFix {
+    width: 100%;
+  }
+`;
+
+const StyledEuiDescriptionList = styled(EuiDescriptionList)`
+  margin: ${px(units.half)} ${px(units.half)} 0 ${px(units.half)};
+  .descriptionList__title,
+  .descriptionList__description {
+    border-bottom: ${({ theme }) => theme.eui.euiBorderThin};
+    margin-top: 0;
+    align-items: center;
+    display: flex;
+`;
+
+const ValueContainer = styled.div`
+  display: flex;
+  align-items: center;
+`;
+
+function removeEmptyValues(items: KeyValue[]) {
+  return items.filter(({ value }) => value !== undefined);
+}
+
+export function KeyValueFilterList({
+  icon,
+  title,
+  keyValueList,
+  initialIsOpen = false,
+  onClickFilter,
+}: {
+  title: string;
+  keyValueList: KeyValue[];
+  initialIsOpen?: boolean;
+  icon?: string;
+  onClickFilter: (filter: { key: string; value: any }) => void;
+}) {
+  if (!keyValueList.length) {
+    return null;
+  }
+
+  return (
+    <StyledEuiAccordion
+      initialIsOpen={initialIsOpen}
+      id={title}
+      buttonContent={<AccordionButtonContent icon={icon} title={title} />}
+      buttonClassName="buttonContentContainer"
+    >
+      <StyledEuiDescriptionList type="column">
+        {removeEmptyValues(keyValueList).map(({ key, value }) => {
+          return (
+            <Fragment key={key}>
+              <EuiDescriptionListTitle
+                className="descriptionList__title"
+                style={{ width: '20%' }}
+              >
+                <EuiText size="s" style={{ fontWeight: 'bold' }}>
+                  {key}
+                </EuiText>
+              </EuiDescriptionListTitle>
+              <EuiDescriptionListDescription
+                className="descriptionList__description"
+                style={{ width: '80%' }}
+              >
+                <ValueContainer>
+                  <EuiButtonEmpty
+                    onClick={() => {
+                      onClickFilter({ key, value });
+                    }}
+                    data-test-subj={`filter_by_${key}`}
+                  >
+                    <EuiToolTip
+                      position="top"
+                      content={i18n.translate(
+                        'xpack.apm.keyValueFilterList.actionFilterLabel',
+                        { defaultMessage: 'Filter by value' }
+                      )}
+                    >
+                      <EuiIcon type="filter" color="black" size="m" />
+                    </EuiToolTip>
+                  </EuiButtonEmpty>
+                  <EuiText size="s">{value}</EuiText>
+                </ValueContainer>
+              </EuiDescriptionListDescription>
+            </Fragment>
+          );
+        })}
+      </StyledEuiDescriptionList>
+    </StyledEuiAccordion>
+  );
+}
+
+function AccordionButtonContent({
+  icon,
+  title,
+}: {
+  icon?: string;
+  title: string;
+}) {
+  return (
+    <EuiFlexGroup responsive={false} gutterSize="s">
+      {icon && (
+        <EuiFlexItem grow={false}>
+          <EuiIcon
+            type={icon}
+            size="l"
+            title={title}
+            data-test-subj="accordion_title_icon"
+          />
+        </EuiFlexItem>
+      )}
+      <EuiFlexItem grow={false}>
+        <EuiText>{title}</EuiText>
+      </EuiFlexItem>
+    </EuiFlexGroup>
+  );
+}
diff --git a/x-pack/plugins/apm/public/components/shared/key_value_filter_list/key_value_filter_list.test.tsx b/x-pack/plugins/apm/public/components/shared/key_value_filter_list/key_value_filter_list.test.tsx
new file mode 100644
index 0000000000000..78a7698259e7a
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/shared/key_value_filter_list/key_value_filter_list.test.tsx
@@ -0,0 +1,90 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import React from 'react';
+import { KeyValueFilterList } from './';
+import {
+  expectTextsInDocument,
+  renderWithTheme,
+} from '../../../utils/testHelpers';
+import { fireEvent } from '@testing-library/react';
+
+describe('KeyValueFilterList', () => {
+  it('hides accordion when key value list is empty', () => {
+    const { container } = renderWithTheme(
+      <KeyValueFilterList
+        title="foo"
+        keyValueList={[]}
+        onClickFilter={jest.fn}
+      />
+    );
+    expect(container).toBeEmptyDOMElement();
+  });
+  it('shows list of key value pairs', () => {
+    const component = renderWithTheme(
+      <KeyValueFilterList
+        title="title"
+        keyValueList={[
+          { key: 'foo', value: 'foo value' },
+          { key: 'bar', value: 'bar value' },
+        ]}
+        onClickFilter={jest.fn}
+      />
+    );
+    expectTextsInDocument(component, [
+      'title',
+      'foo',
+      'foo value',
+      'bar',
+      'bar value',
+    ]);
+  });
+  it('shows icon and title on accordion', () => {
+    const component = renderWithTheme(
+      <KeyValueFilterList
+        title="title"
+        icon="alert"
+        keyValueList={[
+          { key: 'foo', value: 'foo value' },
+          { key: 'bar', value: 'bar value' },
+        ]}
+        onClickFilter={jest.fn}
+      />
+    );
+    expect(component.getByTestId('accordion_title_icon')).toBeInTheDocument();
+    expectTextsInDocument(component, ['title']);
+  });
+  it('hides icon and only shows title on accordion', () => {
+    const component = renderWithTheme(
+      <KeyValueFilterList
+        title="title"
+        keyValueList={[
+          { key: 'foo', value: 'foo value' },
+          { key: 'bar', value: 'bar value' },
+        ]}
+        onClickFilter={jest.fn}
+      />
+    );
+    expect(component.queryAllByTestId('accordion_title_icon')).toEqual([]);
+    expectTextsInDocument(component, ['title']);
+  });
+  it('returns selected key value when the filter button is clicked', () => {
+    const mockFilter = jest.fn();
+    const component = renderWithTheme(
+      <KeyValueFilterList
+        title="title"
+        keyValueList={[
+          { key: 'foo', value: 'foo value' },
+          { key: 'bar', value: 'bar value' },
+        ]}
+        onClickFilter={mockFilter}
+      />
+    );
+
+    fireEvent.click(component.getByTestId('filter_by_foo'));
+    expect(mockFilter).toHaveBeenCalledWith({ key: 'foo', value: 'foo value' });
+  });
+});
diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts b/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts
new file mode 100644
index 0000000000000..25935bcc37dff
--- /dev/null
+++ b/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts
@@ -0,0 +1,84 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import {
+  SERVICE_NAME,
+  SERVICE_NODE_NAME,
+  TRANSACTION_TYPE,
+} from '../../../common/elasticsearch_fieldnames';
+import { environmentQuery, kqlQuery, rangeQuery } from '../../utils/queries';
+import { withApmSpan } from '../../utils/with_apm_span';
+import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions';
+import { Setup, SetupTimeRange } from '../helpers/setup_request';
+
+export interface KeyValue {
+  key: string;
+  value: any | undefined;
+}
+
+export async function getServiceInstanceMetadataDetails({
+  serviceName,
+  serviceNodeName,
+  setup,
+  searchAggregatedTransactions,
+  transactionType,
+  environment,
+  kuery,
+}: {
+  serviceName: string;
+  serviceNodeName: string;
+  setup: Setup & SetupTimeRange;
+  searchAggregatedTransactions: boolean;
+  transactionType: string;
+  environment?: string;
+  kuery?: string;
+}) {
+  return withApmSpan('get_service_instance_metadata_details', async () => {
+    const { start, end, apmEventClient } = setup;
+    const filter = [
+      { term: { [SERVICE_NAME]: serviceName } },
+      { term: { [SERVICE_NODE_NAME]: serviceNodeName } },
+      { term: { [TRANSACTION_TYPE]: transactionType } },
+      ...rangeQuery(start, end),
+      ...environmentQuery(environment),
+      ...kqlQuery(kuery),
+    ];
+
+    const response = await apmEventClient.search({
+      apm: {
+        events: [
+          getProcessorEventForAggregatedTransactions(
+            searchAggregatedTransactions
+          ),
+        ],
+      },
+      body: {
+        terminate_after: 1,
+        size: 1,
+        query: { bool: { filter } },
+      },
+    });
+
+    const sample = response.hits.hits[0]?._source;
+
+    if (!sample) {
+      return {};
+    }
+
+    const { agent, service, container, kubernetes, host, cloud } = sample;
+
+    return {
+      '@timestamp': sample['@timestamp'],
+      agent,
+      service,
+      container,
+      kubernetes,
+      host,
+      cloud,
+    };
+  });
+}
diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts
index 30aa4cce45d04..a27c7d5ba38d2 100644
--- a/x-pack/plugins/apm/server/routes/services.ts
+++ b/x-pack/plugins/apm/server/routes/services.ts
@@ -18,6 +18,7 @@ import { getServices } from '../lib/services/get_services';
 import { getServiceAgentName } from '../lib/services/get_service_agent_name';
 import { getServiceAlerts } from '../lib/services/get_service_alerts';
 import { getServiceDependencies } from '../lib/services/get_service_dependencies';
+import { getServiceInstanceMetadataDetails } from '../lib/services/get_service_instance_metadata_details';
 import { getServiceErrorGroupPeriods } from '../lib/services/get_service_error_groups/get_service_error_group_detailed_statistics';
 import { getServiceErrorGroupMainStatistics } from '../lib/services/get_service_error_groups/get_service_error_group_main_statistics';
 import { getServiceInstancesDetailedStatisticsPeriods } from '../lib/services/get_service_instances/detailed_statistics';
@@ -551,7 +552,44 @@ const serviceInstancesDetailedStatisticsRoute = createApmServerRoute({
   },
 });
 
-const serviceDependenciesRoute = createApmServerRoute({
+export const serviceInstancesMetadataDetails = createApmServerRoute({
+  endpoint:
+    'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}',
+  params: t.type({
+    path: t.type({
+      serviceName: t.string,
+      serviceNodeName: t.string,
+    }),
+    query: t.intersection([
+      t.type({ transactionType: t.string }),
+      environmentRt,
+      kueryRt,
+      rangeRt,
+    ]),
+  }),
+  options: { tags: ['access:apm'] },
+  handler: async (resources) => {
+    const setup = await setupRequest(resources);
+    const { serviceName, serviceNodeName } = resources.params.path;
+    const { transactionType, environment, kuery } = resources.params.query;
+
+    const searchAggregatedTransactions = await getSearchAggregatedTransactions(
+      setup
+    );
+
+    return await getServiceInstanceMetadataDetails({
+      searchAggregatedTransactions,
+      setup,
+      serviceName,
+      serviceNodeName,
+      transactionType,
+      environment,
+      kuery,
+    });
+  },
+});
+
+export const serviceDependenciesRoute = createApmServerRoute({
   endpoint: 'GET /api/apm/services/{serviceName}/dependencies',
   params: t.type({
     path: t.type({
@@ -724,6 +762,7 @@ export const serviceRouteRepository = createApmServerRouteRepository()
   .add(serviceAnnotationsCreateRoute)
   .add(serviceErrorGroupsMainStatisticsRoute)
   .add(serviceErrorGroupsDetailedStatisticsRoute)
+  .add(serviceInstancesMetadataDetails)
   .add(serviceThroughputRoute)
   .add(serviceInstancesMainStatisticsRoute)
   .add(serviceInstancesDetailedStatisticsRoute)
diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/metric_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/metric_raw.ts
index c79a35093df52..d7d015fd21da5 100644
--- a/x-pack/plugins/apm/typings/es_schemas/raw/metric_raw.ts
+++ b/x-pack/plugins/apm/typings/es_schemas/raw/metric_raw.ts
@@ -6,14 +6,22 @@
  */
 
 import { APMBaseDoc } from './apm_base_doc';
+import { Cloud } from './fields/cloud';
 import { Container } from './fields/container';
+import { Host } from './fields/host';
 import { Kubernetes } from './fields/kubernetes';
+import { Service } from './fields/service';
 
 type BaseMetric = APMBaseDoc & {
   processor: {
     name: 'metric';
     event: 'metric';
   };
+  cloud?: Cloud;
+  container?: Container;
+  kubernetes?: Kubernetes;
+  service?: Service;
+  host?: Host;
 };
 
 type BaseBreakdownMetric = BaseMetric & {
@@ -86,8 +94,6 @@ type TransactionDurationMetric = BaseMetric & {
     environment?: string;
     version?: string;
   };
-  container?: Container;
-  kubernetes?: Kubernetes;
 };
 
 export type SpanDestinationMetric = BaseMetric & {
diff --git a/x-pack/test/apm_api_integration/tests/index.ts b/x-pack/test/apm_api_integration/tests/index.ts
index df1ed1db5900a..7c38f37093fa4 100644
--- a/x-pack/test/apm_api_integration/tests/index.ts
+++ b/x-pack/test/apm_api_integration/tests/index.ts
@@ -73,6 +73,10 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte
       loadTestFile(require.resolve('./service_overview/instances_detailed_statistics'));
     });
 
+    describe('service_overview/instance_details', function () {
+      loadTestFile(require.resolve('./service_overview/instance_details'));
+    });
+
     // Services
     describe('services/agent_name', function () {
       loadTestFile(require.resolve('./services/agent_name'));
diff --git a/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instance_details.snap b/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instance_details.snap
new file mode 100644
index 0000000000000..b4197c7dfbf67
--- /dev/null
+++ b/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instance_details.snap
@@ -0,0 +1,47 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`APM API tests basic apm_8.0.0 Instance details when data is loaded fetch instance details return the correct data 1`] = `
+Object {
+  "@timestamp": "2020-12-08T13:59:01.971Z",
+  "agent": Object {
+    "ephemeral_id": "d27b2271-06b4-48c8-a02a-cfd963c0b4d0",
+    "name": "java",
+    "version": "1.19.1-SNAPSHOT.null",
+  },
+  "container": Object {
+    "id": "02950c4c5fbb0fda1cc98c47bf4024b473a8a17629db6530d95dcee68bd54c6c",
+  },
+  "host": Object {
+    "architecture": "amd64",
+    "ip": "10.8.4.45",
+    "os": Object {
+      "platform": "Linux",
+    },
+  },
+  "kubernetes": Object {
+    "pod": Object {
+      "name": "opbeans-java-6bdd78cb5c-k2qz6",
+      "uid": "805e875d-1fda-42c0-bb54-23eb6faf54ab",
+    },
+  },
+  "service": Object {
+    "environment": "production",
+    "framework": Object {
+      "name": "Servlet API",
+    },
+    "language": Object {
+      "name": "Java",
+      "version": "11.0.9.1",
+    },
+    "name": "opbeans-java",
+    "node": Object {
+      "name": "02950c4c5fbb0fda1cc98c47bf4024b473a8a17629db6530d95dcee68bd54c6c",
+    },
+    "runtime": Object {
+      "name": "Java",
+      "version": "11.0.9.1",
+    },
+    "version": "2020-12-08 03:35:36",
+  },
+}
+`;
diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts b/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts
new file mode 100644
index 0000000000000..ee3966aa10a49
--- /dev/null
+++ b/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts
@@ -0,0 +1,101 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import url from 'url';
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../../common/ftr_provider_context';
+import archives from '../../common/fixtures/es_archiver/archives_metadata';
+import { registry } from '../../common/registry';
+import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi';
+
+type ServiceOverviewInstanceDetails = APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>;
+
+export default function ApiTest({ getService }: FtrProviderContext) {
+  const supertest = getService('supertest');
+
+  const archiveName = 'apm_8.0.0';
+  const { start, end } = archives[archiveName];
+
+  registry.when(
+    'Instance details when data is not loaded',
+    { config: 'basic', archives: [] },
+    () => {
+      describe('when data is not loaded', () => {
+        it('handles empty state', async () => {
+          const response = await supertest.get(
+            url.format({
+              pathname: '/api/apm/services/opbeans-java/service_overview_instances/details/foo',
+              query: {
+                start,
+                end,
+                transactionType: 'request',
+              },
+            })
+          );
+
+          expect(response.status).to.be(200);
+          expect(response.body).to.eql({});
+        });
+      });
+    }
+  );
+
+  registry.when(
+    'Instance details when data is loaded',
+    { config: 'basic', archives: [archiveName] },
+    () => {
+      describe('fetch instance details', () => {
+        let response: {
+          status: number;
+          body: ServiceOverviewInstanceDetails;
+        };
+
+        before(async () => {
+          response = await supertest.get(
+            url.format({
+              pathname:
+                '/api/apm/services/opbeans-java/service_overview_instances/details/02950c4c5fbb0fda1cc98c47bf4024b473a8a17629db6530d95dcee68bd54c6c',
+              query: {
+                start,
+                end,
+                transactionType: 'request',
+              },
+            })
+          );
+        });
+
+        it('returns the instance details', () => {
+          expect(response.body).to.not.eql({});
+        });
+
+        it('return the correct data', () => {
+          expectSnapshot(response.body).toMatch();
+        });
+      });
+    }
+  );
+
+  registry.when(
+    'Instance details when data is loaded but details not found',
+    { config: 'basic', archives: [archiveName] },
+    () => {
+      it('handles empty state when instance id not found', async () => {
+        const response = await supertest.get(
+          url.format({
+            pathname: '/api/apm/services/opbeans-java/service_overview_instances/details/foo',
+            query: {
+              start,
+              end,
+              transactionType: 'request',
+            },
+          })
+        );
+        expect(response.status).to.be(200);
+        expect(response.body).to.eql({});
+      });
+    }
+  );
+}