With Active Record associations, we can streamline these - and other - operations by declaratively telling Rails that there is a connection between the two models.
Associations are implemented using macro-style calls, so that you can declaratively add features to your models
A belongs_to association sets up a one-to-one connection with another model, such that each instance of the declaring model "belongs to" one instance of the other model.
belongs_to associations must use the singular term.
belongs_to
A has_one association also sets up a one-to-one connection with another model, but with somewhat different semantics (and consequences).
This association indicates that each instance of a model contains or possesses one instance of another model
belongs_to
A has_many association indicates a one-to-many connection with another model.
This association indicates that each instance of the model has zero or more instances of another model.
belongs_to
A has_many :through association is often used to set up a many-to-many connection with another model
This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model.
through:
through:
The collection of join models can be managed via the API
new join models are created for newly associated objects, and if some are gone their rows are deleted.
The has_many :through association is also useful for setting up "shortcuts" through nested has_many associations
A has_one :through association sets up a one-to-one connection with another model. This association indicates
that the declaring model can be matched with one instance of another model by proceeding through a third model.
A has_and_belongs_to_many association creates a direct many-to-many connection with another model, with no intervening model.
id: false
The has_one relationship says that one of something is yours
using t.references :supplier instead.
declare a many-to-many relationship is to use has_many :through. This makes the association indirectly, through a join model
set up a has_many :through relationship if you need to work with the relationship model as an independent entity
set up a has_and_belongs_to_many relationship (though you'll need to remember to create the joining table in the database).
use has_many :through if you need validations, callbacks, or extra attributes on the join model
With polymorphic associations, a model can belong to more than one other model, on a single association.
belongs_to :imageable, polymorphic: true
a polymorphic belongs_to declaration as setting up an interface that any other model can use.
In designing a data model, you will sometimes find a model that should have a relation to itself
add a references column to the model itself
Controlling caching
Avoiding name collisions
Updating the schema
Controlling association scope
Bi-directional associations
All of the association methods are built around caching, which keeps the result of the most recent query available for further operations.
it is a bad idea to give an association a name that is already used for an instance method of ActiveRecord::Base. The association method would override the base method and break things.
You are responsible for maintaining your database schema to match your associations.
belongs_to associations you need to create foreign keys
has_and_belongs_to_many associations you need to create the appropriate join table
If you create an association some time after you build the underlying model, you need to remember to create an add_column migration to provide the necessary foreign key.
Active Record creates the name by using the lexical order of the class names
So a join between customer and order models will give the default join table name of "customers_orders" because "c" outranks "o" in lexical ordering.
For example, one would expect the tables "paper_boxes" and "papers" to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", but it in fact generates a join table name of "paper_boxes_papers" (because the underscore '' is lexicographically _less than 's' in common encodings).
id: false
pass id: false to create_table because that table does not represent a model
By default, associations look for objects only within the current module's scope.
will work fine, because both the Supplier and the Account class are defined within the same scope.
To associate a model with a model in a different namespace, you must specify the complete class name in your association declaration:
意思是說第一次比較兩者的 first_name 是相同的;但透過 c 實體修改 first_name 之後,再次比較就不相同了,因為兩個是記憶體裡面兩個不同的物件。
preventing inconsistencies and making your application more efficient
Every association will attempt to automatically find the inverse association
and set the :inverse_of option heuristically (based on the association name)
In database terms, this association says that this class contains the foreign key.
In all of these methods, association is replaced with the symbol passed as the first argument to belongs_to.
(force_reload = false)
The association method returns the associated object, if any. If no associated object is found, it returns nil.
the cached version will be returned.
The association= method assigns an associated object to this object.
Behind the scenes, this means extracting the primary key from the associate object and setting this object's foreign key to the same value.
The build_association method returns a new object of the associated type
but the associated object will not yet be saved.
The create_association method returns a new object of the associated type
once it passes all of the validations specified on the associated model, the associated object will be saved
raises ActiveRecord::RecordInvalid if the record is invalid.
finding the number of belonging objects more efficient.
Although the :counter_cache option is specified on the model that includes the belongs_to declaration, the actual column must be added to the associated model.
add a column named orders_count to the Customer model.
:destroy, when the object is destroyed, destroy will be called on its
associated objects.
deleted directly from the database without calling their destroy method.
Rails will not create foreign key columns for you
The :inverse_of option specifies the name of the has_many or has_one association that is the inverse of this association
set the :touch option to :true, then the updated_at or updated_on timestamp on the associated object will be set to the current time whenever this object is saved or destroyed
specify a particular timestamp attribute to update
If you set the :validate option to true, then associated objects will be validated whenever you save this object
By default, this is false: associated objects will not be validated when this object is saved.
where
includes
readonly
select
make your code somewhat more efficient
no need to use includes for immediate associations
will be read-only when retrieved via the association
The select method lets you override the SQL SELECT clause that is used to retrieve data about the associated object
using the association.nil?
Assigning an object to a belongs_to association does not automatically save the object. It does not save the associated object either.
In database terms, this association says that the other class contains the foreign key.
In all of these methods, collection is replaced with the symbol passed as the first argument to has_many, and collection_singular is replaced with the singularized version of that symbol.
The collection<< method adds one or more objects to the collection by setting their foreign keys to the primary key of the calling model
The collection.delete method removes one or more objects from the collection by setting their foreign keys to NULL.
objects will be destroyed if they're associated with dependent: :destroy, and deleted if they're associated with dependent: :delete_all
The collection.destroy method removes one or more objects from the collection by running destroy on each object.
The collection_singular_ids method returns an array of the ids of the objects in the collection.
The collection_singular_ids= method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate
The default strategy for has_many :through associations is delete_all, and for has_many associations is to set the foreign keys to NULL.
The collection.clear method removes all objects from the collection according to the strategy specified by the dependent option
uses the same syntax and options as ActiveRecord::Base.find
The collection.where method finds objects within the collection based on the conditions supplied but the objects are loaded lazily meaning that the database is queried only when the object(s) are accessed.
The collection.build method returns one or more new objects of the associated type. These objects will be instantiated from the passed attributes, and the link through their foreign key will be created, but the associated objects will not yet be saved.
The collection.create method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be created, and, once it passes all of the validations specified on the associated model, the associated object will be saved.
:delete_all causes all the associated objects to be deleted directly from the database (so callbacks will not execute)
:nullify causes the foreign keys to be set to NULL. Callbacks are not executed.
where
includes
readonly
select
:conditions
:through
:polymorphic
:foreign_key
By convention, Rails assumes that the column used to hold the primary key of the association is id. You can override this and explicitly specify the primary key with the :primary_key option.
The :source option specifies the source association name for a has_many :through association.
You only need to use this option if the name of the source association cannot be automatically inferred from the association name.
The :source_type option specifies the source association type for a has_many :through association that proceeds through a polymorphic association.
The :through option specifies a join model through which to perform the query.
has_many :through associations provide a way to implement many-to-many relationships,
By default, this is true: associated objects will be validated when this object is saved.
where
extending
group
includes
limit
offset
order
readonly
select
uniq
If you use a hash-style where option, then record creation via this association will be automatically scoped using the hash
The extending method specifies a named module to extend the association proxy.
Association extensions
The group method supplies an attribute name to group the result set by, using a GROUP BY clause in the finder SQL.
has_many :line_items, -> { group 'orders.id' }, through: :orders
more efficient by including line items in the association from customers to orders
The limit method lets you restrict the total number of objects that will be fetched through an association.
The offset method lets you specify the starting offset for fetching objects via an association
The order method dictates the order in which associated objects will be received (in the syntax used by an SQL ORDER BY clause).
Use the distinct method to keep the collection free of duplicates.
mostly useful together with the :through option
-> { distinct }
.all.inspect
If you want to make sure that, upon insertion, all of the records in the
persisted association are distinct (so that you can be sure that when you
inspect the association that you will never find duplicate records), you should
add a unique index on the table itself
unique: true
Do not attempt to use include? to enforce distinctness
in an association.
multiple users could be attempting this
at the same time
checking for uniqueness using something like include? is subject
to race conditions
When you assign an object to a has_many association, that object is automatically saved (in order to update its foreign key).
If any of these saves fails due to validation errors, then the assignment statement returns false and the assignment itself is cancelled.
If the parent object (the one declaring the has_many association) is unsaved (that is, new_record? returns true) then the child objects are not saved when they are added
All unsaved members of the association will automatically be saved when the parent is saved.
assign an object to a has_many association without saving the object, use the collection.build method
If the join table for a has_and_belongs_to_many association has additional columns beyond the two foreign keys, these columns will be added as attributes to records retrieved via that association.
Records returned with additional attributes will always be read-only
If you require this sort of complex behavior on the table that joins two models in a many-to-many relationship, you should use a has_many :through association instead of has_and_belongs_to_many.
aliased as collection.concat and collection.push.
The collection.delete method removes one or more objects from the collection by deleting records in the join table
not destroy the objects
The collection.destroy method removes one or more objects from the collection by running destroy on each record in the join table, including running callbacks.
not destroy the objects.
The collection.clear method removes every object from the collection by deleting the rows from the joining table.
not destroy the associated objects.
The collection.find method finds objects within the collection. It uses the same syntax and options as ActiveRecord::Base.find.
The collection.where method finds objects within the collection based on the conditions supplied but the objects are loaded lazily meaning that the database is queried only when the object(s) are accessed.
The collection.exists? method checks whether an object meeting the supplied
conditions exists in the collection.
The collection.build method returns a new object of the associated type.
the associated object will not yet be saved.
the associated object will be saved.
The collection.create method returns a new object of the associated type.
it passes all of the validations specified on the associated model
The :foreign_key and :association_foreign_key options are useful when setting up a many-to-many self-join.
Rails assumes that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix _id added.
If you set the :autosave option to true, Rails will save any loaded members and destroy members that are marked for destruction whenever you save the parent object.
By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix _id added.
By default, this is true: associated objects will be validated when this object is saved.
where
extending
group
includes
limit
offset
order
readonly
select
uniq
set conditions via a hash
In this case, using @parts.assemblies.create or @parts.assemblies.build will create orders where the factory column has the value "Seattle"
If you use a hash-style where, then record creation via this association will be automatically scoped using the hash
using a GROUP BY clause in the finder SQL.
Use the uniq method to remove duplicates from the collection.
assign an object to a has_and_belongs_to_many association, that object is automatically saved (in order to update the join table).
If any of these saves fails due to validation errors, then the assignment statement returns false and the assignment itself is cancelled.
If the parent object (the one declaring the has_and_belongs_to_many association) is unsaved (that is, new_record? returns true) then the child objects are not saved when they are added.
If you want to assign an object to a has_and_belongs_to_many association without saving the object, use the collection.build method.
Normal callbacks hook into the life cycle of Active Record objects, allowing you to work with those objects at various points
define association callbacks by adding options to the association declaration
Rails passes the object being added or removed to the callback.
stack callbacks on a single event by passing them as an array
If a before_add callback throws an exception, the object does not get added to the collection.
if a before_remove callback throws an exception, the object does not get removed from the collection
extend these objects through anonymous modules, adding new finders, creators, or other methods.
order_number
use a named extension module
proxy_association.owner returns the object that the association is a part of.
"Recording a terminal session may be important in helping someone learn a process, sharing information in an understandable way, and also presenting a series of commands in a proper manner. Whatever the purpose, there are many times when copy-pasting text from the terminal won't be very helpful while capturing a video of the process is quite far-fetched and may not be always possible. In this quick guide, we will take a look at the easiest way to record and share a terminal session in .gif format."
In my opinion, understanding how a technology works under the hood is the best way to achieve learning speed and to build confidence that you are using the tool in the correct way.
The top-level layer may be read by a union-ing file system (AUFS on my docker implementation) to present a single cohesive view of all the changes as one read-only file system
A git rebase copies the commits from the current branch, and puts these copied commits on top of the specified branch.
The branch that we're rebasing always has the latest changes that we want to keep!
A git rebase changes the history of the project as new hashes are created for the copied commits!
Rebasing is great whenever you're working on a feature branch, and the master branch has been updated.
An interactive rebase can also be useful on the branch you're currently working on, and want to modify some commits.
A git reset gets rid of all the current staged files and gives us control over where HEAD should point to.
A soft reset moves HEAD to the specified commit (or the index of the commit compared to HEAD)
Git should simply reset its state back to where it was on the specified commit: this even includes the changes in your working directory and staged files!
By reverting a certain commit, we create a new commit that contains the reverted changes!
Performing a git revert is very useful in order to undo a certain commit, without modifying the history of the branch.
By cherry-picking a commit, we create a new commit on our active branch that contains the changes that were introduced by the cherry-picked commit.
a fetch simply downloads new data.
A git pull is actually two commands in one: a git fetch, and a git merge
git reflog is a very useful command in order to show a log of all the actions that have been taken
CMD instruction should be used to run the software contained by your
image, along with any arguments
CMD should be given an interactive shell (bash, python,
perl, etc)
COPY them individually, rather than all at once
COPY
is preferred
using ADD to fetch packages from remote URLs is
strongly discouraged
always use COPY
The best use for ENTRYPOINT is to set the image's main command, allowing that
image to be run as though it was that command (and then use CMD as the
default flags).
the image name can double as a reference to the binary as
shown in the command above
ENTRYPOINT instruction can also be used in combination with a helper
script
The VOLUME instruction should be used to expose any database storage area,
configuration storage, or files/folders created by your docker container.
use USER to change to a non-root
user
avoid installing or using sudo
avoid switching USER back
and forth frequently.
always use absolute paths for your
WORKDIR
ONBUILD is only useful for images that are going to be built FROM a given
image
The “onbuild” image will
fail catastrophically if the new build's context is missing the resource being
added.
Docker builds images automatically by reading the instructions from a
Dockerfile -- a text file that contains all commands, in order, needed to
build a given image.
A Docker image consists of read-only layers each of which represents a
Dockerfile instruction.
The layers are stacked and each one is a delta of the
changes from the previous layer
When you run an image and generate a container, you add a new writable layer
(the “container layer”) on top of the underlying layers.
By “ephemeral,” we mean that the container can be stopped
and destroyed, then rebuilt and replaced with an absolute minimum set up and
configuration.
Inadvertently including files that are not necessary for building an image
results in a larger build context and larger image size.
To exclude files not relevant to the build (without restructuring your source
repository) use a .dockerignore file. This file supports exclusion patterns
similar to .gitignore files.
minimize image layers by leveraging build cache.
if your build contains several layers, you can order them from the
less frequently changed (to ensure the build cache is reusable) to the more
frequently changed
avoid
installing extra or unnecessary packages just because they might be “nice to
have.”
Each container should have only one concern.
Decoupling applications into
multiple containers makes it easier to scale horizontally and reuse containers
Limiting each container to one process is a good rule of thumb, but it is not a
hard and fast rule.
Use your best judgment to keep containers as clean and modular as possible.
do multi-stage builds
and only copy the artifacts you need into the final image. This allows you to
include tools and debug information in your intermediate build stages without
increasing the size of the final image.
avoid duplication of packages and make the
list much easier to update.
When building an image, Docker steps through the instructions in your
Dockerfile, executing each in the order specified.
the next
instruction is compared against all child images derived from that base
image to see if one of them was built using the exact same instruction. If
not, the cache is invalidated.
simply comparing the instruction in the Dockerfile with one
of the child images is sufficient.
For the ADD and COPY instructions, the contents of the file(s)
in the image are examined and a checksum is calculated for each file.
If anything has changed in the file(s), such
as the contents and metadata, then the cache is invalidated.
cache checking does not look at the
files in the container to determine a cache match.
In that case just
the command string itself is used to find a match.
Whenever possible, use current official repositories as the basis for your
images.
Using RUN apt-get update && apt-get install -y ensures your Dockerfile
installs the latest package versions with no further coding or manual
intervention.
cache busting
Docker executes these commands using the /bin/sh -c interpreter, which only
evaluates the exit code of the last operation in the pipe to determine success.
set -o pipefail && to ensure that an unexpected error prevents the
build from inadvertently succeeding.
The CMD instruction should be used to run the software contained by your
image, along with any arguments.
CMD should almost always be used in the form
of CMD [“executable”, “param1”, “param2”…]
CMD should rarely be used in the manner of CMD [“param”, “param”] in
conjunction with ENTRYPOINT
The ENV instruction is also useful for providing required environment
variables specific to services you wish to containerize,
Each ENV line creates a new intermediate layer, just like RUN commands
COPY
is preferred
COPY only
supports the basic copying of local files into the container
the best use for ADD is local tar file
auto-extraction into the image, as in ADD rootfs.tar.xz /
If you have multiple Dockerfile steps that use different files from your
context, COPY them individually, rather than all at once.
using ADD to fetch packages from remote URLs is
strongly discouraged; you should use curl or wget instead
The best use for ENTRYPOINT is to set the image’s main command, allowing that
image to be run as though it was that command (and then use CMD as the
default flags).
the image name can double as a reference to the binary as
shown in the command
The VOLUME instruction should be used to expose any database storage area,
configuration storage, or files/folders created by your docker container.
use VOLUME for any mutable and/or user-serviceable
parts of your image
If you absolutely need
functionality similar to sudo, such as initializing the daemon as root but
running it as non-root), consider using “gosu”.
always use absolute paths for your
WORKDIR
An ONBUILD command executes after the current Dockerfile build completes.
Think
of the ONBUILD command as an instruction the parent Dockerfile gives
to the child Dockerfile
A Docker build executes ONBUILD commands before any command in a child
Dockerfile.
Be careful when putting ADD or COPY in ONBUILD. The “onbuild” image
fails catastrophically if the new build’s context is missing the resource being
added.
The release stage takes the build produced by the build stage and combines it with the deploy’s current config.
is ready for immediate execution in the execution environment.
The run stage (also known as “runtime”) runs the app in the execution environment
strict separation between the build, release, and run stages.
the Capistrano deployment tool stores releases in a subdirectory named releases, where the current release is a symlink to the current release directory.
Every release should always have a unique release ID
Releases are an append-only ledger and a release cannot be mutated once it is created.
Caching persists data between the same job in different Workflow builds.
Artifacts persist data after a Workflow has finished
When a Workspace is declared in a job, one or more files or directories can be added. Each addition creates a new layer in the Workspace filesystem. Downstreams jobs can then use this Workspace for its own needs or add more layers on top.
Unlike caching, Workspaces are not shared between runs as they no longer exists once a Workflow is complete.
Caching lets you reuse the data from expensive fetch operations from previous jobs.
A prime example is package dependency managers such as Yarn, Bundler, or Pip.
Caches are global within a project, a cache saved on one branch will be used by others so they should only be used for data that is OK to share across Branches
Artifacts are used for longer-term storage of the outputs of your build process.
If your project needs to be packaged in some form or fashion, say an Android app where the .apk file is uploaded to Google Play, that’s a great example of an artifact.
"CircleCI 2.0 provides a number of different ways to move data into and out of jobs, persist data, and with the introduction of Workspaces, move data between jobs"
Putting this information in a secret
is safer and more flexible than putting it verbatim in a
PodThe smallest and simplest Kubernetes object. A Pod represents a set of running containers on your cluster. definition or in a container imageStored instance of a container that holds a set of software needed to run an application.
.
A Secret is an object that contains a small amount of sensitive data such as
a password, a token, or a key.
Users can create secrets, and the system also creates some secrets.
To use a secret, a pod needs to reference the secret.
A secret can be used with a pod in two ways: as files in a
volumeA directory containing data, accessible to the containers in a pod. mounted on one or more of
its containers, or used by kubelet when pulling images for the pod.
--from-file
You can also create a Secret in a file first, in json or yaml format,
and then create that object.
The
Secret contains two maps:
data and stringData.
The data field is used to store arbitrary data, encoded using
base64.
Kubernetes automatically creates secrets which contain credentials for
accessing the API and it automatically modifies your pods to use this type of
secret.
kubectl get and kubectl describe avoid showing the contents of a secret by
default.
stringData field is provided for convenience, and allows you to provide
secret data as unencoded strings.
where you are deploying an application
that uses a Secret to store a configuration file, and you want to populate
parts of that configuration file during your deployment process.
a field is specified in both data and stringData, the value from stringData
is used.
The keys of data and stringData must consist of alphanumeric characters,
‘-’, ‘_’ or ‘.’.
Newlines are not valid within these strings and must
be omitted.
When using the base64 utility on Darwin/macOS users should avoid
using the -b option to split long lines.
create a Secret from generators and then apply it to create the object on
the Apiserver.
The generated Secrets name has a suffix appended by hashing the contents.
base64 --decode
Secrets can be mounted as data volumes or be exposed as
environment variablesContainer environment variables are name=value pairs that provide useful information into containers running in a Pod.
to be used by a container in a pod.
Multiple pods can reference the same secret.
Each key in the secret data map becomes the filename under mountPath
each container needs its
own volumeMounts block, but only one .spec.volumes is needed per secret
use .spec.volumes[].secret.items field to change target path of each key:
If .spec.volumes[].secret.items is used, only keys specified in items are projected.
To consume all keys from the secret, all of them must be listed in the items field.
You can also specify the permission mode bits files part of a secret will have.
If you don’t specify any, 0644 is used by default.
JSON spec doesn’t support octal notation, so use the value 256 for
0400 permissions.
Inside the container that mounts a secret volume, the secret keys appear as
files and the secret values are base-64 decoded and stored inside these files.
Mounted Secrets are updated automatically
Kubelet is checking whether the mounted secret is fresh on every periodic sync.
cache propagation delay depends on the chosen cache type
A container using a Secret as a
subPath volume mount will not receive
Secret updates.
Inside a container that consumes a secret in an environment variables, the secret keys appear as
normal environment variables containing the base-64 decoded values of the secret data.
An imagePullSecret is a way to pass a secret that contains a Docker (or other) image registry
password to the Kubelet so it can pull a private image on behalf of your Pod.
a secret
needs to be created before any pods that depend on it.
Secret API objects reside in a namespaceAn abstraction used by Kubernetes to support multiple virtual clusters on the same physical cluster.
.
They can only be referenced by pods in that same namespace.
Individual secrets are limited to 1MiB in size.
Kubelet only supports use of secrets for Pods it gets from the API server.
Secrets must be created before they are consumed in pods as environment
variables unless they are marked as optional.
References to Secrets that do
not exist will prevent the pod from starting.
References via secretKeyRef to keys that do not exist in a named Secret
will prevent the pod from starting.
Once a pod is scheduled, the kubelet will try to fetch the
secret value.
Think carefully before sending your own ssh keys: other users of the cluster may have access to the secret.
Special characters such as $, \*, and ! require escaping.
If the password you are using has special characters, you need to escape them using the \\ character.
You do not need to escape special characters in passwords from files
make that key begin with a dot
Dotfiles in secret volume
.secret-file
a frontend container
which handles user interaction and business logic, but which cannot see the
private key;
a signer container that can see the private key, and responds
to simple signing requests from the frontend
When deploying applications that interact with the secrets API, access should be
limited using authorization policies such as RBAC
watch and list requests for secrets within a namespace are
extremely powerful capabilities and should be avoided
watch and list all secrets in a cluster should be reserved for only the most
privileged, system-level components.
additional
precautions with secret objects, such as avoiding writing them to disk where
possible.
A secret is only sent to a node if a pod on that node requires it
only the
secrets that a pod requests are potentially visible within its containers
each container in a pod has
to request the secret volume in its volumeMounts for it to be visible within
the container.
In the API server secret data is stored in etcdConsistent and highly-available key value store used as Kubernetes’ backing store for all cluster data.
limit access to etcd to admin users
Base64 encoding is not an
encryption method and is considered the same as plain text.
A user who can create a pod that uses a secret can also see the value of that secret.
anyone with root on any node can read any secret from the apiserver,
by impersonating the kubelet.
A chart is a collection of files
that describe a related set of Kubernetes resources.
A single chart
might be used to deploy something simple, like a memcached pod, or
something complex, like a full web app stack with HTTP servers,
databases, caches, and so on.
Charts are created as files laid out in a particular directory tree,
then they can be packaged into versioned archives to be deployed.
A chart is organized as a collection of files inside of a directory.
values.yaml # The default configuration values for this chart
charts/ # A directory containing any charts upon which this chart depends.
templates/ # A directory of templates that, when combined with values,
# will generate valid Kubernetes manifest files.
version: A SemVer 2 version (required)
apiVersion: The chart API version, always "v1" (required)
Every chart must have a version number. A version must follow the
SemVer 2 standard.
non-SemVer names are explicitly
disallowed by the system.
When generating a
package, the helm package command will use the version that it finds
in the Chart.yaml as a token in the package name.
the appVersion field is not related to the version field. It is
a way of specifying the version of the application.
appVersion: The version of the app that this contains (optional). This needn't be SemVer.
If the latest version of a chart in the
repository is marked as deprecated, then the chart as a whole is considered to
be deprecated.
deprecated: Whether this chart is deprecated (optional, boolean)
one chart may depend on any number of other charts.
dependencies can be dynamically linked through the requirements.yaml
file or brought in to the charts/ directory and managed manually.
the preferred method of declaring dependencies is by using a
requirements.yaml file inside of your chart.
A requirements.yaml file is a simple file for listing your
dependencies.
The repository field is the full URL to the chart repository.
you must also use helm repo add to add that repo locally.
helm dependency update
and it will use your dependency file to download all the specified
charts into your charts/ directory for you.
When helm dependency update retrieves charts, it will store them as
chart archives in the charts/ directory.
Managing charts with requirements.yaml is a good way to easily keep
charts updated, and also share requirements information throughout a
team.
All charts are loaded by default.
The condition field holds one or more YAML paths (delimited by commas).
If this path exists in the top parent’s values and resolves to a boolean value,
the chart will be enabled or disabled based on that boolean value.
The tags field is a YAML list of labels to associate with this chart.
all charts with tags can be enabled or disabled by
specifying the tag and a boolean value.
The --set parameter can be used as usual to alter tag and condition values.
Conditions (when set in values) always override tags.
The first condition path that exists wins and subsequent ones for that chart are ignored.
The keys containing the values to be imported can be specified in the parent chart’s requirements.yaml file
using a YAML list. Each item in the list is a key which is imported from the child chart’s exports field.
specifying the key data in our import list, Helm looks in the exports field of the child
chart for data key and imports its contents.
the parent key data is not contained in the parent’s final values. If you need to specify the
parent key, use the ‘child-parent’ format.
To access values that are not contained in the exports key of the child chart’s values, you will need to
specify the source key of the values to be imported (child) and the destination path in the parent chart’s
values (parent).
To drop a dependency into your charts/ directory, use the
helm fetch command
A dependency can be either a chart archive (foo-1.2.3.tgz) or an
unpacked chart directory.
name cannot start with _ or ..
Such files are ignored by the chart loader.
a single release is created with all the objects for the chart and its dependencies.
Helm Chart templates are written in the
Go template language, with the
addition of 50 or so add-on template
functions from the Sprig library and a
few other specialized functions
When
Helm renders the charts, it will pass every file in that directory
through the template engine.
Chart developers may supply a file called values.yaml inside of a
chart. This file can contain default values.
Chart users may supply a YAML file that contains values. This can be
provided on the command line with helm install.
When a user supplies custom values, these values will override the
values in the chart’s values.yaml file.
Template files follow the standard conventions for writing Go templates
{{default "minio" .Values.storage}}
Values that are supplied via a values.yaml file (or via the --set
flag) are accessible from the .Values object in a template.
pre-defined, are available to every template, and
cannot be overridden
the names are case
sensitive
Release.Name: The name of the release (not the chart)
Release.IsUpgrade: This is set to true if the current operation is an upgrade or rollback.
Release.Revision: The revision number. It begins at 1, and increments with
each helm upgrade
Chart: The contents of the Chart.yaml
Files: A map-like object containing all non-special files in the chart.
Files can be
accessed using {{index .Files "file.name"}} or using the {{.Files.Get name}} or
{{.Files.GetString name}} functions.
.helmignore
access the contents of the file
as []byte using {{.Files.GetBytes}}
Any unknown Chart.yaml fields will be dropped
Chart.yaml cannot be
used to pass arbitrarily structured data into the template.
A values file is formatted in YAML.
A chart may include a default
values.yaml file
be merged into the default
values file.
The default values file included inside of a chart must be named
values.yaml
accessible inside of templates using the
.Values object
Values files can declare values for the top-level chart, as well as for
any of the charts that are included in that chart’s charts/ directory.
Charts at a higher level have access to all of the variables defined
beneath.
lower level charts cannot access things in
parent charts
Values are namespaced, but namespaces are pruned.
the scope of the values has been reduced and the
namespace prefix removed
Helm supports special “global” value.
a way of sharing one top-level variable with all
subcharts, which is useful for things like setting metadata properties
like labels.
If a subchart declares a global variable, that global will be passed
downward (to the subchart’s subcharts), but not upward to the parent
chart.
global variables of parent charts take precedence over the global variables from subcharts.
helm lint
A chart repository is an HTTP server that houses one or more packaged
charts
Any HTTP server that can serve YAML files and tar files and can answer
GET requests can be used as a repository server.
Helm does not provide tools for uploading charts to
remote repository servers.
the only way to add a chart to $HELM_HOME/starters is to manually
copy it there.
Helm provides a hook mechanism to allow chart developers to intervene
at certain points in a release’s life cycle.
Execute a Job to back up a database before installing a new chart,
and then execute a second job after the upgrade in order to restore
data.
Hooks are declared as an annotation in the metadata section of a manifest
Hooks work like regular templates, but they have special annotations
pre-install
post-install: Executes after all resources are loaded into Kubernetes
pre-delete
post-delete: Executes on a deletion request after all of the release’s
resources have been deleted.
pre-upgrade
post-upgrade
pre-rollback
post-rollback: Executes on a rollback request after all resources
have been modified.
crd-install
test-success: Executes when running helm test and expects the pod to
return successfully (return code == 0).
test-failure: Executes when running helm test and expects the pod to
fail (return code != 0).
Hooks allow you, the chart developer, an opportunity to perform
operations at strategic points in a release lifecycle
Tiller then loads the hook with the lowest weight first (negative to positive)
Tiller returns the release name (and other data) to the client
If the resources is a Job kind, Tiller
will wait until the job successfully runs to completion.
if the job
fails, the release will fail. This is a blocking operation, so the
Helm client will pause while the Job is run.
If they
have hook weights (see below), they are executed in weighted order. Otherwise,
ordering is not guaranteed.
good practice to add a hook weight, and set it
to 0 if weight is not important.
The resources that a hook creates are not tracked or managed as part of the
release.
leave the hook resource alone.
To destroy such
resources, you need to either write code to perform this operation in a pre-delete
or post-delete hook or add "helm.sh/hook-delete-policy" annotation to the hook template file.
Hooks are just Kubernetes manifest files with special annotations in the
metadata section
One resource can implement multiple hooks
no limit to the number of different resources that
may implement a given hook.
When subcharts declare hooks, those are also evaluated. There is no way
for a top-level chart to disable the hooks declared by subcharts.
Hook weights can be positive or negative numbers but must be represented as
strings.
sort those hooks in ascending order.
Hook deletion policies
"before-hook-creation" specifies Tiller should delete the previous hook before the new hook is launched.
By default Tiller will wait for 60 seconds for a deleted hook to no longer exist in the API server before timing out.
Custom Resource Definitions (CRDs) are a special kind in Kubernetes.
The crd-install hook is executed very early during an installation, before
the rest of the manifests are verified.
A common reason why the hook resource might already exist is that it was not deleted following use on a previous install/upgrade.
Helm uses Go templates for templating
your resource files.
two special template functions: include and required
include
function allows you to bring in another template, and then pass the results to other
template functions.
The required function allows you to declare a particular
values entry as required for template rendering.
If the value is empty, the template
rendering will fail with a user submitted error message.
When you are working with string data, you are always safer quoting the
strings than leaving them as bare words
Quote Strings, Don’t Quote Integers
when working with integers do not quote the values
env variables values which are expected to be string
to include a template, and then perform an operation
on that template’s output, Helm has a special include function
The above includes a template called toYaml, passes it $value, and
then passes the output of that template to the nindent function.
Go provides a way for setting template options to control behavior
when a map is indexed with a key that’s not present in the map
The required function gives developers the ability to declare a value entry
as required for template rendering.
The tpl function allows developers to evaluate strings as templates inside a template.
Rendering a external configuration file
(.Files.Get "conf/app.conf")
Image pull secrets are essentially a combination of registry, username, and password.
Automatically Roll Deployments When ConfigMaps or Secrets change
configmaps or secrets are injected as configuration
files in containers
a restart may be required should those
be updated with a subsequent helm upgrade
The sha256sum function can be used to ensure a deployment’s
annotation section is updated if another file changes
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
helm upgrade --recreate-pods
"helm.sh/resource-policy": keep
resources that should not be deleted when Helm runs a
helm delete
this resource becomes
orphaned. Helm will no longer manage it in any way.
create some reusable parts in your chart
In the templates/ directory, any file that begins with an
underscore(_) is not expected to output a Kubernetes manifest file.
by convention, helper templates and partials are placed in a
_helpers.tpl file.
The current best practice for composing a complex application from discrete parts
is to create a top-level umbrella chart that
exposes the global configurations, and then use the charts/ subdirectory to
embed each of the components.
SAP’s Converged charts: These charts
install SAP Converged Cloud a full OpenStack IaaS on Kubernetes. All of the charts are collected
together in one GitHub repository, except for a few submodules.
Deis’s Workflow:
This chart exposes the entire Deis PaaS system with one chart. But it’s different
from the SAP chart in that this umbrella chart is built from each component, and
each component is tracked in a different Git repository.
YAML is a superset of JSON
any valid JSON structure ought to be valid in YAML.
As a best practice, templates should follow a YAML-like syntax unless
the JSON syntax substantially reduces the risk of a formatting issue.
There are functions in Helm that allow you to generate random data,
cryptographic keys, and so on.
a chart repository is a location where packaged charts can be
stored and shared.
A chart repository is an HTTP server that houses an index.yaml file and
optionally some packaged charts.
Because a chart repository can be any HTTP server that can serve YAML and tar
files and can answer GET requests, you have a plethora of options when it comes
down to hosting your own chart repository.
It is not required that a chart package be located on the same server as the
index.yaml file.
A valid chart repository must have an index file. The
index file contains information about each chart in the chart repository.
The Helm project provides an open-source Helm repository server called ChartMuseum that you can host yourself.
$ helm repo index fantastic-charts --url https://fantastic-charts.storage.googleapis.com
A repository will not be added if it does not contain a valid
index.yaml
add the repository to their helm client via the helm
repo add [NAME] [URL] command with any name they would like to use to
reference the repository.
Helm has provenance tools which help chart users verify the integrity and origin
of a package.
Integrity is established by comparing a chart to a provenance record
The provenance file contains a chart’s YAML file plus several pieces of
verification information
Chart repositories serve as a centralized collection of Helm charts.
Chart repositories must make it possible to serve provenance files over HTTP via
a specific request, and must make them available at the same URI path as the chart.
We don’t want to be “the certificate authority” for all chart
signers. Instead, we strongly favor a decentralized model, which is part
of the reason we chose OpenPGP as our foundational technology.
The Keybase platform provides a public
centralized repository for trust information.
A chart contains a number of Kubernetes resources and components that work together.
A test in a helm chart lives under the templates/ directory and is a pod definition that specifies a container with a given command to run.
The pod definition must contain one of the helm test hook annotations: helm.sh/hook: test-success or helm.sh/hook: test-failure
helm test
nest your test suite under a tests/ directory like <chart-name>/templates/tests/
Helm will figure out where to install Tiller by reading your Kubernetes
configuration file (usually $HOME/.kube/config). This is the same file
that kubectl uses.
By default, when Tiller is installed, it does not have authentication enabled.
helm repo update
Without a max history set the history is kept indefinitely, leaving a large number of records for helm and tiller to maintain.
helm init --upgrade
Whenever you install a chart, a new release is created.
one chart can
be installed multiple times into the same cluster. And each can be
independently managed and upgraded.
helm list function will show you a list of all deployed releases.
helm delete
helm status
you
can audit a cluster’s history, and even undelete a release (with helm
rollback).
the Helm
server (Tiller).
The Helm client (helm)
brew install kubernetes-helm
Tiller, the server portion of Helm, typically runs inside of your
Kubernetes cluster.
it can also be run locally, and
configured to talk to a remote Kubernetes cluster.
Role-Based Access Control - RBAC for short
create a service account for Tiller with the right roles and permissions to access resources.
run Tiller in an RBAC-enabled Kubernetes cluster.
run kubectl get pods --namespace
kube-system and see Tiller running.
helm inspect
Helm will look for Tiller in the kube-system namespace unless
--tiller-namespace or TILLER_NAMESPACE is set.
For development, it is sometimes easier to work on Tiller locally, and
configure it to connect to a remote Kubernetes cluster.
even when running locally, Tiller will store release
configuration in ConfigMaps inside of Kubernetes.
helm version should show you both
the client and server version.
Tiller stores its data in Kubernetes ConfigMaps, you can safely
delete and re-install Tiller without worrying about losing any data.
helm reset
The --node-selectors flag allows us to specify the node labels required
for scheduling the Tiller pod.
--override allows you to specify properties of Tiller’s
deployment manifest.
helm init --override manipulates the specified properties of the final
manifest (there is no “values” file).
The --output flag allows us skip the installation of Tiller’s deployment
manifest and simply output the deployment manifest to stdout in either
JSON or YAML format.
By default, tiller stores release information in ConfigMaps in the namespace
where it is running.
switch from the default backend to the secrets
backend, you’ll have to do the migration for this on your own.
a beta SQL storage backend that stores release
information in an SQL database (only postgres has been tested so far).
Once you have the Helm Client and Tiller successfully installed, you can
move on to using Helm to manage charts.
Helm requires that kubelet have access to a copy of the socat program to proxy connections to the Tiller API.
A Release is an instance of a chart running in a Kubernetes cluster.
One chart can often be installed many times into the same cluster.
helm init --client-only
helm init --dry-run --debug
A panic in Tiller is almost always the result of a failure to negotiate with the
Kubernetes API server
Tiller and Helm have to negotiate a common version to make sure that they can safely
communicate without breaking API assumptions
helm delete --purge
Helm stores some files in $HELM_HOME, which is
located by default in ~/.helm
A Chart is a Helm package. It contains all of the resource definitions
necessary to run an application, tool, or service inside of a Kubernetes
cluster.
it like the Kubernetes equivalent of a Homebrew formula,
an Apt dpkg, or a Yum RPM file.
A Repository is the place where charts can be collected and shared.
Set the $HELM_HOME environment variable
each time it is installed, a new release is created.
Helm installs charts into Kubernetes, creating a new release for
each installation. And to find new charts, you can search Helm chart
repositories.
chart repository is named
stable by default
helm search shows you all of the available charts
helm inspect
To install a new package, use the helm install command. At its
simplest, it takes only one argument: The name of the chart.
If you want to use your own release name, simply use the
--name flag on helm install
additional configuration steps you can or
should take.
Helm does not wait until all of the resources are running before it
exits. Many charts require Docker images that are over 600M in size, and
may take a long time to install into the cluster.
helm status
helm inspect
values
helm inspect values stable/mariadb
override any of these settings in a YAML formatted file,
and then pass that file during installation.
helm install -f config.yaml stable/mariadb
--values (or -f): Specify a YAML file with overrides.
--set (and its variants --set-string and --set-file): Specify overrides on the command line.
Values that have been --set can be cleared by running helm upgrade with --reset-values
specified.
Chart
designers are encouraged to consider the --set usage when designing the format
of a values.yaml file.
--set-file key=filepath is another variant of --set.
It reads the file and use its content as a value.
inject a multi-line text into values without dealing with indentation in YAML.
An unpacked chart directory
When a new version of a chart is released, or when you want to change
the configuration of your release, you can use the helm upgrade
command.
Kubernetes charts can be large and
complex, Helm tries to perform the least invasive upgrade.
It will only
update things that have changed since the last release
If both are used, --set values are merged into --values with higher precedence.
The helm get command is a useful tool for looking at a release in the
cluster.
helm rollback
A release version is an incremental revision. Every time an install,
upgrade, or rollback happens, the revision number is incremented by 1.
helm history
a release name cannot be
re-used.
you can rollback a
deleted resource, and have it re-activate.
helm repo list
helm repo add
helm repo update
The Chart Development Guide explains how to develop your own
charts.
helm create
helm lint
helm package
Charts that are archived can be loaded into chart repositories.
chart repository server
Tiller can be installed into any namespace.
Limiting Tiller to only be able to install into specific namespaces and/or resource types is controlled by Kubernetes RBAC roles and rolebindings
Release names are unique PER TILLER INSTANCE
Charts should only contain resources that exist in a single namespace.
not recommended to have multiple Tillers configured to manage resources in the same namespace.
a client-side Helm plugin. A plugin is a
tool that can be accessed through the helm CLI, but which is not part of the
built-in Helm codebase.
Helm plugins are add-on tools that integrate seamlessly with Helm. They provide
a way to extend the core feature set of Helm, but without requiring every new
feature to be written in Go and added to the core tool.
Helm plugins live in $(helm home)/plugins
The Helm plugin model is partially modeled on Git’s plugin model
helm referred to as the porcelain layer, with
plugins being the plumbing.
command is the command that this plugin will
execute when it is called.
Environment variables are interpolated before the plugin
is executed.
The command itself is not executed in a shell. So you can’t oneline a shell script.
Helm is able to fetch Charts using HTTP/S
Variables like KUBECONFIG are set for the plugin if they are set in the
outer environment.
In Kubernetes, granting a role to an application-specific service account is a best practice to ensure that your application is operating in the scope that you have specified.
restrict Tiller’s capabilities to install resources to certain namespaces, or to grant a Helm client running access to a Tiller instance.
Service account with cluster-admin role
The cluster-admin role is created by default in a Kubernetes cluster
Deploy Tiller in a namespace, restricted to deploying resources only in that namespace
Deploy Tiller in a namespace, restricted to deploying resources in another namespace
When running a Helm client in a pod, in order for the Helm client to talk to a Tiller instance, it will need certain privileges to be granted.
SSL Between Helm and Tiller
The Tiller authentication model uses client-side SSL certificates.
creating an internal CA, and using both the
cryptographic and identity functions of SSL.
Helm is a powerful and flexible package-management and operations tool for Kubernetes.
default installation applies no security configurations
with a cluster that is well-secured in a private network with no data-sharing or no other users or teams.
With great power comes great responsibility.
Choose the Best Practices you should apply to your helm installation
Role-based access control, or RBAC
Tiller’s gRPC endpoint and its usage by Helm
Kubernetes employ a role-based access control (or RBAC) system (as do modern operating systems) to help mitigate the damage that can be done if credentials are misused or bugs exist.
In the default installation the gRPC endpoint that Tiller offers is available inside the cluster (not external to the cluster) without authentication configuration applied.
Tiller stores its release information in ConfigMaps. We suggest changing the default to Secrets.
release information
charts
charts are a kind of package that not only installs containers you may or may not have validated yourself, but it may also install into more than one namespace.
As with all shared software, in a controlled or shared environment you must validate all software you install yourself before you install it.
Helm’s provenance tools to ensure the provenance and integrity of charts
"Helm will figure out where to install Tiller by reading your Kubernetes configuration file (usually $HOME/.kube/config). This is the same file that kubectl uses."