688 lines
25 KiB
HTML
688 lines
25 KiB
HTML
<!Doctype html>
|
||
<html id="docs">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<link href='https://fonts.googleapis.com/css?family=Roboto:400,100,100italic,300,300italic,400italic,500,500italic,700,700italic,900,900italic' rel='stylesheet' type='text/css'>
|
||
<link rel="stylesheet" href="/css/styles.css"/>
|
||
<script src="/js/script.js"></script>
|
||
<script src="/js/jquery-2.2.0.min.js"></script>
|
||
<script src="/js/non-mini.js"></script>
|
||
<title>Kubernetes - Variable expansion in pod command, args, and env</title>
|
||
</head>
|
||
<body>
|
||
<div id="cellophane" onclick="kub.toggleMenu()"></div>
|
||
<header>
|
||
<a href="/" class="logo"></a>
|
||
<div class="nav-buttons" data-auto-burger="primary">
|
||
<a href="/docs" class="button" id="viewDocs">View Documentation</a>
|
||
<a href="/get-started" class="button" id="tryKubernetes">Try Kubernetes</a>
|
||
<button id="hamburger" onclick="kub.toggleMenu()" data-auto-burger-exclude><div></div></button>
|
||
</div>
|
||
|
||
<nav id="mainNav">
|
||
<main data-auto-burger="primary">
|
||
<div class="nav-box">
|
||
<h3><a href="">Get Started</a></h3>
|
||
<p>Built for a multi-cloud world, public, private or hybrid. Seamlessly roll out new features.</p>
|
||
</div>
|
||
<div class="nav-box">
|
||
<h3><a href="">Documentation</a></h3>
|
||
<p>Pellentesque in ipsum id orci porta dapibus. Nulla porttitor accumsan tincidunt. </p>
|
||
</div>
|
||
<div class="nav-box">
|
||
<h3><a href="">Community</a></h3>
|
||
<p>Vestibulum ac diam sit amet quam vehicula elementum sed sit amet dui. </p>
|
||
</div>
|
||
<div class="nav-box">
|
||
<h3><a href="">Blog</a></h3>
|
||
<p>Curabitur arcu erat, accumsan id imperdiet et, porttitor at sem. Quisque velit nisi, pretium ut lacinia in. </p>
|
||
</div>
|
||
</main>
|
||
<main data-auto-burger="primary">
|
||
<div class="left">
|
||
<h5 class="github-invite">Interested in hacking on the core Kubernetes code base?</h5>
|
||
<a href="" class="button">View On Github</a>
|
||
</div>
|
||
|
||
<div class="right">
|
||
<h5 class="github-invite">Explore the community</h5>
|
||
<div class="social">
|
||
<a href="https://twitter.com/kubernetesio" class="Twitter"><span>twitter</span></a>
|
||
<a href="https://github.com/kubernetes/kubernetes" class="github"><span>Github</span></a>
|
||
<a href="http://slack.k8s.io/" class="slack"><span>Slack</span></a>
|
||
<a href="http://stackoverflow.com/questions/tagged/kubernetes" class="stack-overflow"><span>stackoverflow</span></a>
|
||
<a href="https://groups.google.com/forum/#!forum/google-containers" class="mailing-list"><span>Mailing List</span></a>
|
||
</div>
|
||
</div>
|
||
<div class="clear" style="clear: both"></div>
|
||
</main>
|
||
</nav>
|
||
</header>
|
||
|
||
<!-- HERO -->
|
||
<section id="hero" class="light-text">
|
||
<h1></h1>
|
||
<h5></h5>
|
||
<div id="vendorStrip" class="light-text">
|
||
<ul>
|
||
<li><a href="/v1.1/">GUIDES</a></li>
|
||
<li><a href="/v1.1/reference">REFERENCE</a></li>
|
||
<li><a href="/v1.1/samples">SAMPLES</a></li>
|
||
<li><a href="/v1.1/support">SUPPORT</a></li>
|
||
</ul>
|
||
<div class="dropdown">
|
||
<div class="readout"></div>
|
||
<a href="/v1.1">Version 1.1</a>
|
||
<a href="/v1.0">Version 1.0</a>
|
||
</div>
|
||
<input type="text" id="search" placeholder="Search the docs">
|
||
</div>
|
||
</section>
|
||
|
||
<section id="encyclopedia">
|
||
<div id="docsToc">
|
||
<div class="pi-accordion">
|
||
|
||
|
||
|
||
</div> <!-- /pi-accordion -->
|
||
</div> <!-- /docsToc -->
|
||
<div id="docsContent">
|
||
<h1>Variable expansion in pod command, args, and env</h1>
|
||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||
|
||
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||
|
||
<h1 id="variable-expansion-in-pod-command-args-and-env">Variable expansion in pod command, args, and env</h1>
|
||
|
||
<h2 id="abstract">Abstract</h2>
|
||
|
||
<p>A proposal for the expansion of environment variables using a simple <code>$(var)</code> syntax.</p>
|
||
|
||
<h2 id="motivation">Motivation</h2>
|
||
|
||
<p>It is extremely common for users to need to compose environment variables or pass arguments to
|
||
their commands using the values of environment variables. Kubernetes should provide a facility for
|
||
the 80% cases in order to decrease coupling and the use of workarounds.</p>
|
||
|
||
<h2 id="goals">Goals</h2>
|
||
|
||
<ol>
|
||
<li>Define the syntax format</li>
|
||
<li>Define the scoping and ordering of substitutions</li>
|
||
<li>Define the behavior for unmatched variables</li>
|
||
<li>Define the behavior for unexpected/malformed input</li>
|
||
</ol>
|
||
|
||
<h2 id="constraints-and-assumptions">Constraints and Assumptions</h2>
|
||
|
||
<ul>
|
||
<li>This design should describe the simplest possible syntax to accomplish the use-cases</li>
|
||
<li>Expansion syntax will not support more complicated shell-like behaviors such as default values
|
||
(viz: <code>$(VARIABLE_NAME:"default")</code>), inline substitution, etc.</li>
|
||
</ul>
|
||
|
||
<h2 id="use-cases">Use Cases</h2>
|
||
|
||
<ol>
|
||
<li>As a user, I want to compose new environment variables for a container using a substitution
|
||
syntax to reference other variables in the container’s environment and service environment
|
||
variables</li>
|
||
<li>As a user, I want to substitute environment variables into a container’s command</li>
|
||
<li>As a user, I want to do the above without requiring the container’s image to have a shell</li>
|
||
<li>As a user, I want to be able to specify a default value for a service variable which may
|
||
not exist</li>
|
||
<li>As a user, I want to see an event associated with the pod if an expansion fails (ie, references
|
||
variable names that cannot be expanded)</li>
|
||
</ol>
|
||
|
||
<h3 id="use-case-composition-of-environment-variables">Use Case: Composition of environment variables</h3>
|
||
|
||
<p>Currently, containers are injected with docker-style environment variables for the services in
|
||
their pod’s namespace. There are several variables for each service, but users routinely need
|
||
to compose URLs based on these variables because there is not a variable for the exact format
|
||
they need. Users should be able to build new environment variables with the exact format they need.
|
||
Eventually, it should also be possible to turn off the automatic injection of the docker-style
|
||
variables into pods and let the users consume the exact information they need via the downward API
|
||
and composition.</p>
|
||
|
||
<h4 id="expanding-expanded-variables">Expanding expanded variables</h4>
|
||
|
||
<p>It should be possible to reference an variable which is itself the result of an expansion, if the
|
||
referenced variable is declared in the container’s environment prior to the one referencing it.
|
||
Put another way – a container’s environment is expanded in order, and expanded variables are
|
||
available to subsequent expansions.</p>
|
||
|
||
<h3 id="use-case-variable-expansion-in-command">Use Case: Variable expansion in command</h3>
|
||
|
||
<p>Users frequently need to pass the values of environment variables to a container’s command.
|
||
Currently, Kubernetes does not perform any expansion of variables. The workaround is to invoke a
|
||
shell in the container’s command and have the shell perform the substitution, or to write a wrapper
|
||
script that sets up the environment and runs the command. This has a number of drawbacks:</p>
|
||
|
||
<ol>
|
||
<li>Solutions that require a shell are unfriendly to images that do not contain a shell</li>
|
||
<li>Wrapper scripts make it harder to use images as base images</li>
|
||
<li>Wrapper scripts increase coupling to Kubernetes</li>
|
||
</ol>
|
||
|
||
<p>Users should be able to do the 80% case of variable expansion in command without writing a wrapper
|
||
script or adding a shell invocation to their containers’ commands.</p>
|
||
|
||
<h3 id="use-case-images-without-shells">Use Case: Images without shells</h3>
|
||
|
||
<p>The current workaround for variable expansion in a container’s command requires the container’s
|
||
image to have a shell. This is unfriendly to images that do not contain a shell (<code>scratch</code> images,
|
||
for example). Users should be able to perform the other use-cases in this design without regard to
|
||
the content of their images.</p>
|
||
|
||
<h3 id="use-case-see-an-event-for-incomplete-expansions">Use Case: See an event for incomplete expansions</h3>
|
||
|
||
<p>It is possible that a container with incorrect variable values or command line may continue to run
|
||
for a long period of time, and that the end-user would have no visual or obvious warning of the
|
||
incorrect configuration. If the kubelet creates an event when an expansion references a variable
|
||
that cannot be expanded, it will help users quickly detect problems with expansions.</p>
|
||
|
||
<h2 id="design-considerations">Design Considerations</h2>
|
||
|
||
<h3 id="what-features-should-be-supported">What features should be supported?</h3>
|
||
|
||
<p>In order to limit complexity, we want to provide the right amount of functionality so that the 80%
|
||
cases can be realized and nothing more. We felt that the essentials boiled down to:</p>
|
||
|
||
<ol>
|
||
<li>Ability to perform direct expansion of variables in a string</li>
|
||
<li>Ability to specify default values via a prioritized mapping function but without support for
|
||
defaults as a syntax-level feature</li>
|
||
</ol>
|
||
|
||
<h3 id="what-should-the-syntax-be">What should the syntax be?</h3>
|
||
|
||
<p>The exact syntax for variable expansion has a large impact on how users perceive and relate to the
|
||
feature. We considered implementing a very restrictive subset of the shell <code>${var}</code> syntax. This
|
||
syntax is an attractive option on some level, because many people are familiar with it. However,
|
||
this syntax also has a large number of lesser known features such as the ability to provide
|
||
default values for unset variables, perform inline substitution, etc.</p>
|
||
|
||
<p>In the interest of preventing conflation of the expansion feature in Kubernetes with the shell
|
||
feature, we chose a different syntax similar to the one in Makefiles, <code>$(var)</code>. We also chose not
|
||
to support the bar <code>$var</code> format, since it is not required to implement the required use-cases.</p>
|
||
|
||
<p>Nested references, ie, variable expansion within variable names, are not supported.</p>
|
||
|
||
<h4 id="how-should-unmatched-references-be-treated">How should unmatched references be treated?</h4>
|
||
|
||
<p>Ideally, it should be extremely clear when a variable reference couldn’t be expanded. We decided
|
||
the best experience for unmatched variable references would be to have the entire reference, syntax
|
||
included, show up in the output. As an example, if the reference <code>$(VARIABLE_NAME)</code> cannot be
|
||
expanded, then <code>$(VARIABLE_NAME)</code> should be present in the output.</p>
|
||
|
||
<h4 id="escaping-the-operator">Escaping the operator</h4>
|
||
|
||
<p>Although the <code>$(var)</code> syntax does overlap with the <code>$(command)</code> form of command substitution
|
||
supported by many shells, because unexpanded variables are present verbatim in the output, we
|
||
expect this will not present a problem to many users. If there is a collision between a variable
|
||
name and command substitution syntax, the syntax can be escaped with the form <code>$$(VARIABLE_NAME)</code>,
|
||
which will evaluate to <code>$(VARIABLE_NAME)</code> whether <code>VARIABLE_NAME</code> can be expanded or not.</p>
|
||
|
||
<h2 id="design">Design</h2>
|
||
|
||
<p>This design encompasses the variable expansion syntax and specification and the changes needed to
|
||
incorporate the expansion feature into the container’s environment and command.</p>
|
||
|
||
<h3 id="syntax-and-expansion-mechanics">Syntax and expansion mechanics</h3>
|
||
|
||
<p>This section describes the expansion syntax, evaluation of variable values, and how unexpected or
|
||
malformed inputs are handled.</p>
|
||
|
||
<h4 id="syntax">Syntax</h4>
|
||
|
||
<p>The inputs to the expansion feature are:</p>
|
||
|
||
<ol>
|
||
<li>A utf-8 string (the input string) which may contain variable references</li>
|
||
<li>A function (the mapping function) that maps the name of a variable to the variable’s value, of
|
||
type <code>func(string) string</code></li>
|
||
</ol>
|
||
|
||
<p>Variable references in the input string are indicated exclusively with the syntax
|
||
<code>$(<variable-name>)</code>. The syntax tokens are:</p>
|
||
|
||
<ul>
|
||
<li><code>$</code>: the operator</li>
|
||
<li><code>(</code>: the reference opener</li>
|
||
<li><code>)</code>: the reference closer</li>
|
||
</ul>
|
||
|
||
<p>The operator has no meaning unless accompanied by the reference opener and closer tokens. The
|
||
operator can be escaped using <code>$$</code>. One literal <code>$</code> will be emitted for each <code>$$</code> in the input.</p>
|
||
|
||
<p>The reference opener and closer characters have no meaning when not part of a variable reference.
|
||
If a variable reference is malformed, viz: <code>$(VARIABLE_NAME</code> without a closing expression, the
|
||
operator and expression opening characters are treated as ordinary characters without special
|
||
meanings.</p>
|
||
|
||
<h4 id="scope-and-ordering-of-substitutions">Scope and ordering of substitutions</h4>
|
||
|
||
<p>The scope in which variable references are expanded is defined by the mapping function. Within the
|
||
mapping function, any arbitrary strategy may be used to determine the value of a variable name.
|
||
The most basic implementation of a mapping function is to use a <code>map[string]string</code> to lookup the
|
||
value of a variable.</p>
|
||
|
||
<p>In order to support default values for variables like service variables presented by the kubelet,
|
||
which may not be bound because the service that provides them does not yet exist, there should be a
|
||
mapping function that uses a list of <code>map[string]string</code> like:</p>
|
||
|
||
<div class="highlight">
|
||
<pre><code class="language-go">func MakeMappingFunc(maps ...map[string]string) func(string) string {
|
||
return func(input string) string {
|
||
for _, context := range maps {
|
||
val, ok := context[input]
|
||
if ok {
|
||
return val
|
||
}
|
||
}
|
||
|
||
return ""
|
||
}
|
||
}
|
||
|
||
// elsewhere
|
||
containerEnv := map[string]string{
|
||
"FOO": "BAR",
|
||
"ZOO": "ZAB",
|
||
"SERVICE2_HOST": "some-host",
|
||
}
|
||
|
||
serviceEnv := map[string]string{
|
||
"SERVICE_HOST": "another-host",
|
||
"SERVICE_PORT": "8083",
|
||
}
|
||
|
||
// single-map variation
|
||
mapping := MakeMappingFunc(containerEnv)
|
||
|
||
// default variables not found in serviceEnv
|
||
mappingWithDefaults := MakeMappingFunc(serviceEnv, containerEnv)
|
||
</code></pre>
|
||
</div>
|
||
|
||
<h3 id="implementation-changes">Implementation changes</h3>
|
||
|
||
<p>The necessary changes to implement this functionality are:</p>
|
||
|
||
<ol>
|
||
<li>Add a new interface, <code>ObjectEventRecorder</code>, which is like the <code>EventRecorder</code> interface, but
|
||
scoped to a single object, and a function that returns an <code>ObjectEventRecorder</code> given an
|
||
<code>ObjectReference</code> and an <code>EventRecorder</code></li>
|
||
<li>Introduce <code>third_party/golang/expansion</code> package that provides:
|
||
<ol>
|
||
<li>An <code>Expand(string, func(string) string) string</code> function</li>
|
||
<li>A <code>MappingFuncFor(ObjectEventRecorder, ...map[string]string) string</code> function</li>
|
||
</ol>
|
||
</li>
|
||
<li>Make the kubelet expand environment correctly</li>
|
||
<li>Make the kubelet expand command correctly</li>
|
||
</ol>
|
||
|
||
<h4 id="event-recording">Event Recording</h4>
|
||
|
||
<p>In order to provide an event when an expansion references undefined variables, the mapping function
|
||
must be able to create an event. In order to facilitate this, we should create a new interface in
|
||
the <code>api/client/record</code> package which is similar to <code>EventRecorder</code>, but scoped to a single object:</p>
|
||
|
||
<div class="highlight">
|
||
<pre><code class="language-go">// ObjectEventRecorder knows how to record events about a single object.
|
||
type ObjectEventRecorder interface {
|
||
// Event constructs an event from the given information and puts it in the queue for sending.
|
||
// 'reason' is the reason this event is generated. 'reason' should be short and unique; it will
|
||
// be used to automate handling of events, so imagine people writing switch statements to
|
||
// handle them. You want to make that easy.
|
||
// 'message' is intended to be human readable.
|
||
//
|
||
// The resulting event will be created in the same namespace as the reference object.
|
||
Event(reason, message string)
|
||
|
||
// Eventf is just like Event, but with Sprintf for the message field.
|
||
Eventf(reason, messageFmt string, args ...interface{})
|
||
|
||
// PastEventf is just like Eventf, but with an option to specify the event's 'timestamp' field.
|
||
PastEventf(timestamp unversioned.Time, reason, messageFmt string, args ...interface{})
|
||
}
|
||
</code></pre>
|
||
</div>
|
||
|
||
<p>There should also be a function that can construct an <code>ObjectEventRecorder</code> from a <code>runtime.Object</code>
|
||
and an <code>EventRecorder</code>:</p>
|
||
|
||
<div class="highlight">
|
||
<pre><code class="language-go">type objectRecorderImpl struct {
|
||
object runtime.Object
|
||
recorder EventRecorder
|
||
}
|
||
|
||
func (r *objectRecorderImpl) Event(reason, message string) {
|
||
r.recorder.Event(r.object, reason, message)
|
||
}
|
||
|
||
func ObjectEventRecorderFor(object runtime.Object, recorder EventRecorder) ObjectEventRecorder {
|
||
return &objectRecorderImpl{object, recorder}
|
||
}
|
||
</code></pre>
|
||
</div>
|
||
|
||
<h4 id="expansion-package">Expansion package</h4>
|
||
|
||
<p>The expansion package should provide two methods:</p>
|
||
|
||
<div class="highlight">
|
||
<pre><code class="language-go">// MappingFuncFor returns a mapping function for use with Expand that
|
||
// implements the expansion semantics defined in the expansion spec; it
|
||
// returns the input string wrapped in the expansion syntax if no mapping
|
||
// for the input is found. If no expansion is found for a key, an event
|
||
// is raised on the given recorder.
|
||
func MappingFuncFor(recorder record.ObjectEventRecorder, context ...map[string]string) func(string) string {
|
||
// ...
|
||
}
|
||
|
||
// Expand replaces variable references in the input string according to
|
||
// the expansion spec using the given mapping function to resolve the
|
||
// values of variables.
|
||
func Expand(input string, mapping func(string) string) string {
|
||
// ...
|
||
}
|
||
</code></pre>
|
||
</div>
|
||
|
||
<h4 id="kubelet-changes">Kubelet changes</h4>
|
||
|
||
<p>The Kubelet should be made to correctly expand variables references in a container’s environment,
|
||
command, and args. Changes will need to be made to:</p>
|
||
|
||
<ol>
|
||
<li>The <code>makeEnvironmentVariables</code> function in the kubelet; this is used by
|
||
<code>GenerateRunContainerOptions</code>, which is used by both the docker and rkt container runtimes</li>
|
||
<li>The docker manager <code>setEntrypointAndCommand</code> func has to be changed to perform variable
|
||
expansion</li>
|
||
<li>The rkt runtime should be made to support expansion in command and args when support for it is
|
||
implemented</li>
|
||
</ol>
|
||
|
||
<h3 id="examples">Examples</h3>
|
||
|
||
<h4 id="inputs-and-outputs">Inputs and outputs</h4>
|
||
|
||
<p>These examples are in the context of the mapping:</p>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Name</th>
|
||
<th>Value</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>VAR_A</code></td>
|
||
<td><code>"A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>VAR_B</code></td>
|
||
<td><code>"B"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>VAR_C</code></td>
|
||
<td><code>"C"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>VAR_REF</code></td>
|
||
<td><code>$(VAR_A)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>VAR_EMPTY</code></td>
|
||
<td><code>""</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>No other variables are defined.</p>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Input</th>
|
||
<th>Result</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>"$(VAR_A)"</code></td>
|
||
<td><code>"A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"___$(VAR_B)___"</code></td>
|
||
<td><code>"___B___"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"___$(VAR_C)"</code></td>
|
||
<td><code>"___C"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_A)-$(VAR_A)"</code></td>
|
||
<td><code>"A-A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_A)-1"</code></td>
|
||
<td><code>"A-1"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_A)_$(VAR_B)_$(VAR_C)"</code></td>
|
||
<td><code>"A_B_C"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$$(VAR_B)_$(VAR_A)"</code></td>
|
||
<td><code>"$(VAR_B)_A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$$(VAR_A)_$$(VAR_B)"</code></td>
|
||
<td><code>"$(VAR_A)_$(VAR_B)"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"f000-$$VAR_A"</code></td>
|
||
<td><code>"f000-$VAR_A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"foo\\$(VAR_C)bar"</code></td>
|
||
<td><code>"foo\Cbar"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"foo\\\\$(VAR_C)bar"</code></td>
|
||
<td><code>"foo\\Cbar"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"foo\\\\\\\\$(VAR_A)bar"</code></td>
|
||
<td><code>"foo\\\\Abar"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_A$(VAR_B))"</code></td>
|
||
<td><code>"$(VAR_A$(VAR_B))"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_A$(VAR_B)"</code></td>
|
||
<td><code>"$(VAR_A$(VAR_B)"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_REF)"</code></td>
|
||
<td><code>"$(VAR_A)"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"%%$(VAR_REF)--$(VAR_REF)%%"</code></td>
|
||
<td><code>"%%$(VAR_A)--$(VAR_A)%%"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"foo$(VAR_EMPTY)bar"</code></td>
|
||
<td><code>"foobar"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"foo$(VAR_Awhoops!"</code></td>
|
||
<td><code>"foo$(VAR_Awhoops!"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"f00__(VAR_A)__"</code></td>
|
||
<td><code>"f00__(VAR_A)__"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$?_boo_$!"</code></td>
|
||
<td><code>"$?_boo_$!"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$VAR_A"</code></td>
|
||
<td><code>"$VAR_A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_DNE)"</code></td>
|
||
<td><code>"$(VAR_DNE)"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$$$$$$(BIG_MONEY)"</code></td>
|
||
<td><code>"$$$(BIG_MONEY)"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$$$$$$(VAR_A)"</code></td>
|
||
<td><code>"$$$(VAR_A)"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$$$$$$$(GOOD_ODDS)"</code></td>
|
||
<td><code>"$$$$(GOOD_ODDS)"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$$$$$$$(VAR_A)"</code></td>
|
||
<td><code>"$$$A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$VAR_A)"</code></td>
|
||
<td><code>"$VAR_A)"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"${VAR_A}"</code></td>
|
||
<td><code>"${VAR_A}"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_B)_______$(A"</code></td>
|
||
<td><code>"B_______$(A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_C)_______$("</code></td>
|
||
<td><code>"C_______$("</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(VAR_A)foobarzab$"</code></td>
|
||
<td><code>"Afoobarzab$"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"foo-\\$(VAR_A"</code></td>
|
||
<td><code>"foo-\$(VAR_A"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"--$($($($($--"</code></td>
|
||
<td><code>"--$($($($($--"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$($($($($--foo$("</code></td>
|
||
<td><code>"$($($($($--foo$("</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"foo0--$($($($("</code></td>
|
||
<td><code>"foo0--$($($($("</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>"$(foo$$var)</code></td>
|
||
<td><code>$(foo$$var)</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h4 id="in-a-pod-building-a-url">In a pod: building a URL</h4>
|
||
|
||
<p>Notice the <code>$(var)</code> syntax.</p>
|
||
|
||
<div class="highlight">
|
||
<pre><code class="language-yaml">apiVersion: v1
|
||
kind: Pod
|
||
metadata:
|
||
name: expansion-pod
|
||
spec:
|
||
containers:
|
||
- name: test-container
|
||
image: gcr.io/google_containers/busybox
|
||
command: [ "/bin/sh", "-c", "env" ]
|
||
env:
|
||
- name: PUBLIC_URL
|
||
value: "http://$(GITSERVER_SERVICE_HOST):$(GITSERVER_SERVICE_PORT)"
|
||
restartPolicy: Never
|
||
</code></pre>
|
||
</div>
|
||
|
||
<h4 id="in-a-pod-building-a-url-using-downward-api">In a pod: building a URL using downward API</h4>
|
||
|
||
<div class="highlight">
|
||
<pre><code class="language-yaml">apiVersion: v1
|
||
kind: Pod
|
||
metadata:
|
||
name: expansion-pod
|
||
spec:
|
||
containers:
|
||
- name: test-container
|
||
image: gcr.io/google_containers/busybox
|
||
command: [ "/bin/sh", "-c", "env" ]
|
||
env:
|
||
- name: POD_NAMESPACE
|
||
valueFrom:
|
||
fieldRef:
|
||
fieldPath: "metadata.namespace"
|
||
- name: PUBLIC_URL
|
||
value: "http://gitserver.$(POD_NAMESPACE):$(SERVICE_PORT)"
|
||
restartPolicy: Never
|
||
</code></pre>
|
||
</div>
|
||
|
||
<!-- BEGIN MUNGE: IS_VERSIONED -->
|
||
<!-- TAG IS_VERSIONED -->
|
||
<!-- END MUNGE: IS_VERSIONED -->
|
||
|
||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||
<p><a href=""><img src="https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/design/expansion.md?pixel" alt="Analytics" /></a>
|
||
<!-- END MUNGE: GENERATED_ANALYTICS --></p>
|
||
|
||
|
||
</div>
|
||
</section>
|
||
|
||
|
||
<footer>
|
||
<main class="light-text">
|
||
<nav>
|
||
<a href="/getting-started.html">Getting Started</a>
|
||
<a href="/docs.html">Documentation</a>
|
||
<a href="http://blog.kubernetes.io/">Blog</a>
|
||
<a href="/foobang.html">Community</a>
|
||
</nav>
|
||
<div class="social">
|
||
<a href="https://twitter.com/kubernetesio" class="twitter"><span>twitter</span></a>
|
||
<a href="https://github.com/kubernetes/kubernetes" class="github"><span>Github</span></a>
|
||
<a href="http://slack.k8s.io/" class="slack"><span>Slack</span></a>
|
||
<a href="http://stackoverflow.com/questions/tagged/kubernetes" class="stack-overflow"><span>stackoverflow</span></a>
|
||
<a href="https://groups.google.com/forum/#!forum/google-containers" class="mailing-list"><span>Mailing List</span></a>
|
||
<label for="wishField">I wish this page <input type="text" id="wishField" name="wishField" placeholder="made better textfield suggestions"></label>
|
||
</div>
|
||
<div class="center">© 2016 Kubernetes</div>
|
||
</main>
|
||
</footer>
|
||
|
||
</body>
|
||
</html>
|
||
|
||
|
||
|