diff --git a/config/_subsections/configuring-the-operator.md b/config/_subsections/configuring-the-operator.md index f2d9acd..8aa0b98 100644 --- a/config/_subsections/configuring-the-operator.md +++ b/config/_subsections/configuring-the-operator.md @@ -511,7 +511,7 @@ spec: If you wish to use only **Cryostat's Discovery Plugin API**, set the property `spec.targetDiscoveryOptions.disableBuiltInDiscovery` to `true` to disable **Cryostat's** built-in discovery mechanisms. For more details, see the **Discovery Plugin** section in the [OpenAPI schema](https://github.com/cryostatio/cryostat/blob/main/schema/openapi.yaml). -You may also change the list of port names and port numbers that **Cryostat** uses to discover compatible target Endpoints. By default it looks for ports with the name `jfr-jmx` or with the number `9091`. +You may also change the list of port names and port numbers that **Cryostat** uses to discover compatible target `Endpoint`s. By default it looks for ports with the name `jfr-jmx` or with the number `9091`. ```yaml apiVersion: operator.cryostat.io/v1beta2 diff --git a/config/_subsections/using-the-cryostat-agent.md b/config/_subsections/using-the-cryostat-agent.md index cb35a8f..6713a21 100644 --- a/config/_subsections/using-the-cryostat-agent.md +++ b/config/_subsections/using-the-cryostat-agent.md @@ -19,4 +19,261 @@ The programming interfaces for **Cryostat** and its **Agent** are designed to im More details about the configuration options for the **Cryostat Agent** [are available here](https://github.com/cryostatio/cryostat-agent/blob/{{site.data.versions.cryostat.release-branch}}/README.md#configuration). -For instructions on how to install the **Cryostat Agent** into your applications, [check the Setup section in Getting Started](/get-started/#using-the-cryostat-agent). +### [Advanced Agent Configuration](#advanced-agent-configuration) + +#### [Manually Installing the Cryostat Agent](#manually-installing-the-cryostat-agent) + +If you are: +- not using the **Cryostat Operator** +- unable to deploy an **Agent** to your application +- requiring **JMX** connections only +- requiring no-downtime instrumentation of **Agents** + +then the [Getting Started](/get-started/#using-the-cryostat-agent) automatic **Agent** configuration may not be +suitable for your use case. Below are descriptions of how to manually attach the **Cryostat Agent** to your +application. + +##### [Dynamically Attaching the Cryostat Agent](#dynamically-attaching-the-cryostat-agent) + +Starting with **Cryostat** 3.0 and **Cryostat Agent** 0.4 it is possible to attach the **Cryostat Agent** to your application while the +application is running, with no rebuild, redeployment, or restart. To do this, the **Agent JAR** must still be available in your application's +filesystem (see [above](#statically-attaching-the-cryostat-agent) for details on how and where to acquire it), and you must be able to execute +a new Java process in the same space as the application. + +Let's make this concrete with an example. We will assume you are running your application in **Kubernetes** and that you have manually downloaded +the **Cryostat Agent JAR** to your workstation. + +```bash +$ kubectl cp \ + /path/to/cryostat-agent-shaded.jar \ + -n my-namespace \ + mypod:/tmp/cryostat/cryostat-agent-shaded.jar +$ kubectl exec \ + -n my-namespace \ + mypod -c mycontainer \ + -i -t -- \ + java -jar /tmp/cryostat/cryostat-agent-shaded.jar \ + -Dcryostat.agent.baseuri=http://cryostat:8181 \ + -Dcryostat.agent.authorization.type="kubernetes" \ + -Dcryostat.agent.callback=http://${POD_IP}:9977 \ + -Dcryostat.agent.api.writes-enabled=true +``` + +1. Replace `/path/to/cryostat-agent-shaded.jar` with the real path to the **JAR** on your workstation +2. Replace `my-namespace` with the namespace your application is deployed in +3. Replace `mypod` with the name of your application's Pod +4. Replace `mycontainer` with the name of your application's container within its Pod (or remove this if it is the only container in the Pod) +5. Replace `http://cryostat:8181` with the correct internal Service URL for your **Cryostat** server within the same **Kubernetes** cluster +6. Replace `${POD_IP}` with the application Pod's IP Address as found in its Status using `kubectl get -o yaml` + +By following this procedure you will copy the **Cryostat Agent JAR** into the application's filesystem (`kubectl cp`), then launch the +**Agent** as a Java process (`kubectl exec`). When the **Agent** is launched in this manner it will look for other Java processes. If it +finds exactly one other Java process then it will use that process' Attach API and ask the JVM to load the Agent's **JAR**, passing its +`-D` arguments over and setting them as system properties in the application JVM after the Attach API loads the **JAR**. If you have multiple +Java processes running within the application container then you can either specify a particular PID to the **Cryostat Agent** so that it +only attaches to that JVM, or you can use the wildcard `*` asterisk so that the Agent attaches to every JVM it finds (other than its own +bootstrap JVM). You can run the **Agent** with the `-h` flag to get details about its options: + +```bash +$ java -jar cryostat-agent-{{site.data.versions.agent.version}}-shaded.jar -h +Usage: CryostatAgent [-hV] [-D=]... + [--smartTrigger=]... [@...] + [] +Launcher for Cryostat Agent to self-inject and dynamically attach to workload +JVMs + [@...] One or more argument files containing options. + [] The PID to attach to and attempt to self-inject the + Cryostat Agent. If not specified, the Agent will + look to find exactly one candidate and attach to + that, failing if none or more than one are found. + Otherwise, this should be a process ID, or the '*' + wildcard to request the Agent attempt to attach to + all discovered JVMs. + -D, --property= + Optional property definitions to supply to the + injected Agent copies to add or override property + definitions once the Agent is running in the + workload JVM. These should be specified as key=value + pairs, ex. -Dcryostat.agent.baseuri=http://cryostat. + service.local . May be specified more than once. + -h, --help Show this help message and exit. + --smartTrigger= + Smart Triggers definition. May be specified more than + once. + -V, --version Print version information and exit. +``` + +*Note*: this procedure will only attach the **Cryostat Agent** to the application once, for the application process' current lifecycle. If the +application process is restarted then the **Agent** will no longer be loaded, and you will need to perform the steps above again to re-attach it. +If you scale up your application so there are more Replicas then these additional instances will also not have the **Agent** attached. This +workflow is useful primarily for one-off troubleshooting or profiling scenarios. If you find yourself performing these steps often then +consider [statically attaching the Agent](#statically-attaching-the-cryostat-agent) so that the configuration for attaching it occurs at +every application startup. + +##### [Statically Attaching the Cryostat Agent](#statically-attaching-the-cryostat-agent) + +The **Cryostat Agent** **JAR** must be available to your application **JVM**. The **JAR** asset can be downloaded [directly from upstream](https://github.com/cryostatio/cryostat-agent/packages), +or from [Maven Central](https://mvnrepository.com/artifact/io.cryostat/cryostat-agent). For most use cases the `-shaded` **JAR** would be appropriate. +You may also include the Agent as a dependency in your application's `pom.xml` to automate the download: + +```xml + + ... + + + + maven-dependency-plugin + {{ site.data.versions.maven-plugins.dependency.version }} + + + prepare-package + + copy + + + + + io.cryostat + cryostat-agent + {{ site.data.versions.agent.version }} + shaded + + + true + + + + + + ... + + ... + +``` + +The next time we build our application, the **Cryostat Agent** **JAR** will be located at `target/dependency/cryostat-agent-shaded.jar`. Then we can update our **Dockerfile**: + +```Dockerfile +... +COPY target/dependency/cryostat-agent-shaded.jar /deployments/app/ +... +# Assume we are using an application framework where the JAVA_OPTS environment variable can be used to pass JVM flags +ENV JAVA_OPTS="-javaagent:/deployments/app/cryostat-agent-shaded.jar" +``` + +The **Cryostat Agent** is also available as an **OCI Container Image** on [quay.io](https://quay.io/repository/cryostat/cryostat-agent-init). +We can use this directly in our application **Dockerfile** in a multi-stage build, rather than downloading the **Agent** **JAR** from GitHub or Maven Central: + +```Dockerfile +ARG cryostat_agent_version + +FROM quay.io/cryostat/cryostat-agent-init:${cryostat_agent_version} AS cryostat_agent + +FROM ${application_base_img} +COPY --from=cryostat_agent /cryostat/agent/cryostat-agent-shaded.jar /deployments/app/cryostat-agent-shaded.jar +... +# Assume we are using an application framework where the JAVA_OPTS environment variable can be used to pass JVM flags +ENV JAVA_OPTS="-javaagent:/deployments/app/cryostat-agent-shaded.jar" +``` + +Next we must rebuild our container image. This is specific to your application but will likely look something like +`docker build -t docker.io/myorg/myapp:latest -f src/main/docker/Dockerfile --build-arg cryostat_agent_version={{ site.data.versions.agent.version }} .` +(omit the `--build-arg` if you are not using the multi-stage build step above). Push that updated image or otherwise get it updated in your +**Kubernetes** registry, then modify your application `Deployment` to supply **JVM** system properties or environment variables configuring +the **Cryostat Agent**: + +```yaml +apiVersion: apps/v1 +kind: Deployment +... +spec: + ... + template: + ... + spec: + containers: + - name: sample-app + image: docker.io/myorg/myapp:latest + env: + - name: CRYOSTAT_AGENT_APP_NAME + # Replace this with any value you like to use to identify your application. + value: "myapp" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + # Update this to correspond to the name of your Cryostat instance + # if it is not 'cryostat'. + - name: CRYOSTAT_INSTANCE_NAME + value: cryostat + - name: CRYOSTAT_AGENT_BASEURI + # This assumes that the target application # and the Cryostat instance are in the same + # Namespace, but you may choose to configure the Agent to communicate with a Cryostat in + # a different Namespace, too. + # (https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/) + value: https://$(CRYOSTAT_INSTANCE_NAME).$(NAMESPACE).svc.cluster.local:4180 + - name: CRYOSTAT_AGENT_API_WRITES_ENABLED + # Set this to 'true' to turn on the "write" or "mutation" capabilities of the + # Agent's HTTP API. This defaults to 'false', so the Agent HTTP API only exposes + # readonly access to certain low-sensitivity calls. If this is 'true' then the + # Agent will allow Cryostat to dynamically request JFR recordings to be started, + # stopped, deleted, etc. as well as listed and retrieved. + value: true + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: CRYOSTAT_AGENT_CALLBACK + # This infers the Agent Callback directly from the Pod's IP address using the + # Kubernetes Downward API. Use this value directly as provided. The port number + # 9977 can be changed but must match the containerPort below. + value: "http://$(POD_IP):9977" + # This tells the Agent to look for its Kubernetes serviceaccount token mounted to + # its own Pod at the default filesystem path, and use the token there for Bearer + # Authorization to the Cryostat instance. This should be the correct behaviour in + # most scenarios and allows you to configure the serviceaccount's authorization by + # using standard Kubernetes RBAC for the application Pod's serviceaccount. + - name: CRYOSTAT_AGENT_AUTHORIZATION_TYPE + value: kubernetes + + # These two environment variables should not be set in a production environment. + # For development and testing it can be useful to disable TLS trust and hostname + # verification. In practice, you should provide the Agent with the Cryostat instance's + # TLS certificate so that the Agent can trust it and only establish connections to + # that trusted instance. Configuration of the Agent's TLS trust is covered elsewhere. + - name: CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUST_ALL + value: "true" + - name: CRYOSTAT_AGENT_WEBCLIENT_TLS_VERIFY_HOSTNAME + value: "false" + ports: + - containerPort: 9977 + protocol: TCP + resources: {} + restartPolicy: Always +status: {} +``` + +Port number `9977` is the default HTTP port that the **Agent** exposes for its internal webserver that services **Cryostat** requests. +If this port number conflicts with another port used by your application, be sure to change both the `ports.containerPort` spec +as well as the `CRYOSTAT_AGENT_CALLBACK` environment variable. + +Finally, create a `Service` to enable **Cryostat** to make requests to this **Agent**: + +```yaml +apiVersion: v1 +kind: Service +... +spec: + ports: + - name: "cryostat-agent" + port: 9977 + targetPort: 9977 +... +``` + +You may also be interested in using the **Cryostat Agent** for application discovery, but using **JMX** for remote management and data +access rather than the **Cryostat Agent** HTTP API. In that case, simply set `CRYOSTAT_AGENT_API_WRITES_ENABLED=false` to turn off as much +of the **Cryostat Agent** HTTP API as possible, then continue to [the next section](#using-jmx) to additionally configure your application +to enable and expose **JMX** for remote management and data access. If the **Cryostat Agent** detects that the application it is attached +to has **JMX** enabled then it will publish itself to the **Cryostat** server with both an **Agent** HTTP URL and a **JMX** URL. If **JMX** +is not detected then it will only publish the HTTP URL. diff --git a/config/index.md b/config/index.md index d90dae0..05435af 100644 --- a/config/index.md +++ b/config/index.md @@ -10,12 +10,12 @@ title: Cryostat Advanced Configuration {% include_relative _subsections/configuring-the-operator.md %} -{% include_relative _subsections/external-storage.md %} - {% include_relative _subsections/using-the-cryostat-agent.md %} {% include_relative _subsections/configure-agent-harvester.md %} +{% include_relative _subsections/external-storage.md %} + # Additional Information {% include_relative _subsections/operator-architecture.md %} diff --git a/get-started/index.md b/get-started/index.md index 1246ed9..83decd5 100644 --- a/get-started/index.md +++ b/get-started/index.md @@ -251,21 +251,22 @@ If your application uses a later version of **JDK8** with **JFR** support, pleas to learn how to configure your application without the **Cryostat Agent**. The **Cryostat Agent** may even be used with non-Java **JVM** languages, such as Kotlin, Scala, -Clojure, JRuby, or Jython, so long as these are running on a compatible **HotSpot JVM** which +Clojure, JRuby, or Jython, so long as these are running on a compatible **JVM** which implements **JDK Flight Recorder**, allows the attachment of **Agents**, and includes the -`com.sun.net.httpserver` package. Any **OpenJDK 11+** build should be sufficient. +`com.sun.net.httpserver` package. -##### [Automatic Configuration of the Cryostat Agent](#automatic-configuration-of-the-cryostat-agent) +###### [Automatic Configuration of the Cryostat Agent](#automatic-configuration-of-the-cryostat-agent) Since **Cryostat** version 4.0.0, the **Operator** can assist you in automating the use of the **Cryostat Agent** with your applications. By adding the `cryostat.io/name` and `cryostat.io/namespace` labels to your application Pod (or Deployment spec template) you can inform the **Cryostat Operator** that you wish for your application to be -instrumented with the **Cryostat Agent**. The **Operator** will -[dynamically inject](#dynamically-attaching-the-cryostat-agent) the **Agent** to your -application and supply it with the required configuration parameters to register with -the **Cryostat** instance specified by your `cryostat.io/namespace`/`cryostat.io/name` -labels. +instrumented with the **Cryostat Agent**. The **Operator** will mount a **Volume** containing +the **Agent** to your application. It will additonally append the `-javaagent` flag to your +application's `JAVA_TOOL_OPTIONS` environment variable to statically attach the **Agent** at +startup, and will set other environment variables as needed to supply the **Agent** with the +required configuration parameters to register it with the **Cryostat** instance specified by +your `cryostat.io/namespace`/`cryostat.io/name` labels. The following additional labels are available to customize aspects of the injection process: - `cryostat.io/callback-port`: by default the **Agent** uses port `9977` as the `HTTP` port @@ -301,261 +302,11 @@ particular adjustments required: Some adjustments may still be required, depending on the application base image used or any custom application entrypoint scripts. -##### [Manually Installing the Cryostat Agent](#manually-installing-the-cryostat-agent) +###### [Alternative Agent Setups](#alternative-agent-setups) -If you are: -- not using the **Cryostat Operator** -- unable to deploy an **Agent** to your application -- requiring **JMX** connections only -- requiring no-downtime instrumentation of **Agents** - -then the above automatic **Agent** configuration may not be suitable for your use case. -Below are descriptions of how to manually attach the **Cryostat Agent** to your application. - -###### [Dynamically Attaching the Cryostat Agent](#dynamically-attaching-the-cryostat-agent) - -Starting with **Cryostat** 3.0 and **Cryostat Agent** 0.4 it is possible to attach the **Cryostat Agent** to your application while the -application is running, with no rebuild, redeployment, or restart. To do this, the **Agent JAR** must still be available in your application's -filesystem (see [above](#statically-attaching-the-cryostat-agent) for details on how and where to acquire it), and you must be able to execute -a new Java process in the same space as the application. - -Let's make this concrete with an example. We will assume you are running your application in **Kubernetes** and that you have manually downloaded -the **Cryostat Agent JAR** to your workstation. - -```bash -$ kubectl cp \ - /path/to/cryostat-agent-shaded.jar \ - -n my-namespace \ - mypod:/tmp/cryostat/cryostat-agent-shaded.jar -$ kubectl exec \ - -n my-namespace \ - mypod -c mycontainer \ - -i -t -- \ - java -jar /tmp/cryostat/cryostat-agent-shaded.jar \ - -Dcryostat.agent.baseuri=http://cryostat:8181 \ - -Dcryostat.agent.authorization.type="kubernetes" \ - -Dcryostat.agent.callback=http://${POD_IP}:9977 \ - -Dcryostat.agent.api.writes-enabled=true -``` - -1. Replace `/path/to/cryostat-agent-shaded.jar` with the real path to the **JAR** on your workstation -2. Replace `my-namespace` with the namespace your application is deployed in -3. Replace `mypod` with the name of your application's Pod -4. Replace `mycontainer` with the name of your application's container within its Pod (or remove this if it is the only container in the Pod) -5. Replace `http://cryostat:8181` with the correct internal Service URL for your **Cryostat** server within the same **Kubernetes** cluster -6. Replace `${POD_IP}` with the application Pod's IP Address as found in its Status using `kubectl get -o yaml` - -By following this procedure you will copy the **Cryostat Agent JAR** into the application's filesystem (`kubectl cp`), then launch the -**Agent** as a Java process (`kubectl exec`). When the **Agent** is launched in this manner it will look for other Java processes. If it -finds exactly one other Java process then it will use that process' Attach API and ask the JVM to load the Agent's **JAR**, passing its -`-D` arguments over and setting them as system properties in the application JVM after the Attach API loads the **JAR**. If you have multiple -Java processes running within the application container then you can either specify a particular PID to the **Cryostat Agent** so that it -only attaches to that JVM, or you can use the wildcard `*` asterisk so that the Agent attaches to every JVM it finds (other than its own -bootstrap JVM). You can run the **Agent** with the `-h` flag to get details about its options: - -```bash -$ java -jar cryostat-agent-{{site.data.versions.agent.version}}-shaded.jar -h -Usage: CryostatAgent [-hV] [-D=]... - [--smartTrigger=]... [@...] - [] -Launcher for Cryostat Agent to self-inject and dynamically attach to workload -JVMs - [@...] One or more argument files containing options. - [] The PID to attach to and attempt to self-inject the - Cryostat Agent. If not specified, the Agent will - look to find exactly one candidate and attach to - that, failing if none or more than one are found. - Otherwise, this should be a process ID, or the '*' - wildcard to request the Agent attempt to attach to - all discovered JVMs. - -D, --property= - Optional property definitions to supply to the - injected Agent copies to add or override property - definitions once the Agent is running in the - workload JVM. These should be specified as key=value - pairs, ex. -Dcryostat.agent.baseuri=http://cryostat. - service.local . May be specified more than once. - -h, --help Show this help message and exit. - --smartTrigger= - Smart Triggers definition. May be specified more than - once. - -V, --version Print version information and exit. -``` - -*Note*: this procedure will only attach the **Cryostat Agent** to the application once, for the application process' current lifecycle. If the -application process is restarted then the **Agent** will no longer be loaded, and you will need to perform the steps above again to re-attach it. -If you scale up your application so there are more Replicas then these additional instances will also not have the **Agent** attached. This -workflow is useful primarily for one-off troubleshooting or profiling scenarios. If you find yourself performing these steps often then -consider [statically attaching the Agent](#statically-attaching-the-cryostat-agent) so that the configuration for attaching it occurs at -every application startup. - -###### [Statically Attaching the Cryostat Agent](#statically-attaching-the-cryostat-agent) - -The **Cryostat Agent** **JAR** must be available to your application **JVM**. The **JAR** asset can be downloaded [directly from upstream](https://github.com/cryostatio/cryostat-agent/packages), -or from [Maven Central](https://mvnrepository.com/artifact/io.cryostat/cryostat-agent). For most use cases the `-shaded` **JAR** would be appropriate. -You may also include the Agent as a dependency in your application's `pom.xml` to automate the download: - -```xml - - ... - - - - maven-dependency-plugin - {{ site.data.versions.maven-plugins.dependency.version }} - - - prepare-package - - copy - - - - - io.cryostat - cryostat-agent - {{ site.data.versions.agent.version }} - shaded - - - true - - - - - - ... - - ... - -``` - -The next time we build our application, the **Cryostat Agent** **JAR** will be located at `target/dependency/cryostat-agent-shaded.jar`. Then we can update our **Dockerfile**: - -```Dockerfile -... -COPY target/dependency/cryostat-agent-shaded.jar /deployments/app/ -... -# Assume we are using an application framework where the JAVA_OPTS environment variable can be used to pass JVM flags -ENV JAVA_OPTS="-javaagent:/deployments/app/cryostat-agent-shaded.jar" -``` - -The **Cryostat Agent** is also available as an **OCI Container Image** on [quay.io](https://quay.io/repository/cryostat/cryostat-agent-init). -We can use this directly in our application **Dockerfile** in a multi-stage build, rather than downloading the **Agent** **JAR** from GitHub or Maven Central: - -```Dockerfile -ARG cryostat_agent_version - -FROM quay.io/cryostat/cryostat-agent-init:${cryostat_agent_version} AS cryostat_agent - -FROM ${application_base_img} -COPY --from=cryostat_agent /cryostat/agent/cryostat-agent-shaded.jar /deployments/app/cryostat-agent-shaded.jar -... -# Assume we are using an application framework where the JAVA_OPTS environment variable can be used to pass JVM flags -ENV JAVA_OPTS="-javaagent:/deployments/app/cryostat-agent-shaded.jar" -``` - -Next we must rebuild our container image. This is specific to your application but will likely look something like -`docker build -t docker.io/myorg/myapp:latest -f src/main/docker/Dockerfile --build-arg cryostat_agent_version={{ site.data.versions.agent.version }} .` -(omit the `--build-arg` if you are not using the multi-stage build step above). Push that updated image or otherwise get it updated in your -**Kubernetes** registry, then modify your application `Deployment` to supply **JVM** system properties or environment variables configuring -the **Cryostat Agent**: - -```yaml -apiVersion: apps/v1 -kind: Deployment -... -spec: - ... - template: - ... - spec: - containers: - - name: sample-app - image: docker.io/myorg/myapp:latest - env: - - name: CRYOSTAT_AGENT_APP_NAME - # Replace this with any value you like to use to identify your application. - value: "myapp" - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - # Update this to correspond to the name of your Cryostat instance - # if it is not 'cryostat'. - - name: CRYOSTAT_INSTANCE_NAME - value: cryostat - - name: CRYOSTAT_AGENT_BASEURI - # This assumes that the target application # and the Cryostat instance are in the same - # Namespace, but you may choose to configure the Agent to communicate with a Cryostat in - # a different Namespace, too. - # (https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/) - value: https://$(CRYOSTAT_INSTANCE_NAME).$(NAMESPACE).svc.cluster.local:4180 - - name: CRYOSTAT_AGENT_API_WRITES_ENABLED - # Set this to 'true' to turn on the "write" or "mutation" capabilities of the - # Agent's HTTP API. This defaults to 'false', so the Agent HTTP API only exposes - # readonly access to certain low-sensitivity calls. If this is 'true' then the - # Agent will allow Cryostat to dynamically request JFR recordings to be started, - # stopped, deleted, etc. as well as listed and retrieved. - value: true - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: CRYOSTAT_AGENT_CALLBACK - # This infers the Agent Callback directly from the Pod's IP address using the - # Kubernetes Downward API. Use this value directly as provided. The port number - # 9977 can be changed but must match the containerPort below. - value: "http://$(POD_IP):9977" - # This tells the Agent to look for its Kubernetes serviceaccount token mounted to - # its own Pod at the default filesystem path, and use the token there for Bearer - # Authorization to the Cryostat instance. This should be the correct behaviour in - # most scenarios and allows you to configure the serviceaccount's authorization by - # using standard Kubernetes RBAC for the application Pod's serviceaccount. - - name: CRYOSTAT_AGENT_AUTHORIZATION_TYPE - value: kubernetes - - # These two environment variables should not be set in a production environment. - # For development and testing it can be useful to disable TLS trust and hostname - # verification. In practice, you should provide the Agent with the Cryostat instance's - # TLS certificate so that the Agent can trust it and only establish connections to - # that trusted instance. Configuration of the Agent's TLS trust is covered elsewhere. - - name: CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUST_ALL - value: "true" - - name: CRYOSTAT_AGENT_WEBCLIENT_TLS_VERIFY_HOSTNAME - value: "false" - ports: - - containerPort: 9977 - protocol: TCP - resources: {} - restartPolicy: Always -status: {} -``` - -Port number `9977` is the default HTTP port that the **Agent** exposes for its internal webserver that services **Cryostat** requests. -If this port number conflicts with another port used by your application, be sure to change both the `ports.containerPort` spec -as well as the `CRYOSTAT_AGENT_CALLBACK` environment variable. - -Finally, create a `Service` to enable **Cryostat** to make requests to this **Agent**: - -```yaml -apiVersion: v1 -kind: Service -... -spec: - ports: - - name: "cryostat-agent" - port: 9977 - targetPort: 9977 -... -``` - -You may also be interested in using the **Cryostat Agent** for application discovery, but using **JMX** for remote management and data -access rather than the **Cryostat Agent** HTTP API. In that case, simply set `CRYOSTAT_AGENT_API_WRITES_ENABLED=false` to turn off as much -of the **Cryostat Agent** HTTP API as possible, then continue to [the next section](#using-jmx) to additionally configure your application -to enable and expose **JMX** for remote management and data access. If the **Cryostat Agent** detects that the application it is attached -to has **JMX** enabled then it will publish itself to the **Cryostat** server with both an **Agent** HTTP URL and a **JMX** URL. If **JMX** -is not detected then it will only publish the HTTP URL. +The **Cryostat Agent** can also be used in an ad-hoc dynamic attachment mode, or statically attached to your +application at startup. For more information on these configurations, check the +[advanced Agent configuration](/config/#advanced-agent-configuration) document. ##### [Using JMX](#using-jmx) **Cryostat** is also able to use Java Management Extensions (**JMX**) to communicate with target applications. This is a standard JDK feature that can be enabled by passing **JVM** @@ -567,10 +318,9 @@ flags to your application at startup. A basic and insecure setup suitable for te -Dcom.sun.management.jmxremote.authenticate=false ``` -[comment]: # TODO explain how to configure SSL and auth for JMX, or link to external docs - It is recommended that you enable both `SSL` and authentication on your application. You can then [trust the certificate](/guides/#add-a-trusted-certificate) -and [store the credentials](/guides/#store-credentials). +and [store the credentials](/guides/#store-credentials). Configuration of `SSL` and authentication on the **JVM** +**JMX** server is out of scope of this guide, but resources should be available from your **JVM** vendor. Depending on your application or its framework, you may set these flags directly in a `Dockerfile` entrypoint, an environment variable, or similar. This may or may not require a container image rebuild, and it will require the container to be restarted. Once this is done the application container will be listening for @@ -589,7 +339,7 @@ spec: - name: sample-app image: docker.io/myorg/myapp:latest env: - - name: JAVA_OPTS + - name: JAVA_OPTS_APPEND value: >- -Dcom.sun.management.jmxremote.port=9091 -Dcom.sun.management.jmxremote.ssl=false @@ -612,11 +362,16 @@ spec: ... ``` -**Cryostat** queries the **Kubernetes** API server and looks for `Service`s with a port either named `jfr-jmx` or with the number `9091`. -One or both of these conditions must be met or else **Cryostat** will not automatically detect your -application. In this case you may wish to use the [**Cryostat Agent**](#using-the-cryostat-agent) to enable discovery, while keeping -communications over **JMX** rather than HTTP. If you do use the **Cryostat Agent** for discovery and **JMX** for remote management, -you may combine both of the `Service` definitions into a single `Service` with two exposed `ports`. +**Cryostat** queries the **Kubernetes** API server and looks for `EndpointSlice`s with a port either named `jfr-jmx` or +with the number `9091`. One or both of these conditions must be met or else **Cryostat** +will not automatically detect your application. The creation of a `Service` will trigger the creation of an +`EndpointSlice` object for each `Pod` behind the `Service`, with each `EndpointSlice` reflecting the `Service` port and +unique `Pod` IP address, so that **Cryostat** is able to enumerate all of the **Target** application `Pod`s without +going through the indirection of a `Service` or getting confused due to `LoadBalancer` behaviour. + +If the port name `jfr-jmx` or number `9091` do not work for your application deployment, check the +[advanced configuration](/config/#target-discovery-options) document for information on how to configure **Cryostat** to +look for different names/numbers. ## [Next Steps](#next-steps) Now that you have installed and deployed **Cryostat** and know how to access its