runtime.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package container
  14. import (
  15. "fmt"
  16. "io"
  17. "reflect"
  18. "strings"
  19. "time"
  20. "github.com/golang/glog"
  21. "k8s.io/kubernetes/pkg/api"
  22. "k8s.io/kubernetes/pkg/types"
  23. "k8s.io/kubernetes/pkg/util/flowcontrol"
  24. "k8s.io/kubernetes/pkg/util/term"
  25. "k8s.io/kubernetes/pkg/volume"
  26. )
  27. type Version interface {
  28. // Compare compares two versions of the runtime. On success it returns -1
  29. // if the version is less than the other, 1 if it is greater than the other,
  30. // or 0 if they are equal.
  31. Compare(other string) (int, error)
  32. // String returns a string that represents the version.
  33. String() string
  34. }
  35. // ImageSpec is an internal representation of an image. Currently, it wraps the
  36. // value of a Container's Image field, but in the future it will include more detailed
  37. // information about the different image types.
  38. type ImageSpec struct {
  39. Image string
  40. }
  41. // ImageStats contains statistics about all the images currently available.
  42. type ImageStats struct {
  43. // Total amount of storage consumed by existing images.
  44. TotalStorageBytes uint64
  45. }
  46. // Runtime interface defines the interfaces that should be implemented
  47. // by a container runtime.
  48. // Thread safety is required from implementations of this interface.
  49. type Runtime interface {
  50. // Type returns the type of the container runtime.
  51. Type() string
  52. // Version returns the version information of the container runtime.
  53. Version() (Version, error)
  54. // APIVersion returns the cached API version information of the container
  55. // runtime. Implementation is expected to update this cache periodically.
  56. // This may be different from the runtime engine's version.
  57. // TODO(random-liu): We should fold this into Version()
  58. APIVersion() (Version, error)
  59. // Status returns error if the runtime is unhealthy; nil otherwise.
  60. Status() error
  61. // GetPods returns a list of containers grouped by pods. The boolean parameter
  62. // specifies whether the runtime returns all containers including those already
  63. // exited and dead containers (used for garbage collection).
  64. GetPods(all bool) ([]*Pod, error)
  65. // GarbageCollect removes dead containers using the specified container gc policy
  66. // If allSourcesReady is not true, it means that kubelet doesn't have the
  67. // complete list of pods from all avialble sources (e.g., apiserver, http,
  68. // file). In this case, garbage collector should refrain itself from aggressive
  69. // behavior such as removing all containers of unrecognized pods (yet).
  70. // TODO: Revisit this method and make it cleaner.
  71. GarbageCollect(gcPolicy ContainerGCPolicy, allSourcesReady bool) error
  72. // Syncs the running pod into the desired pod.
  73. SyncPod(pod *api.Pod, apiPodStatus api.PodStatus, podStatus *PodStatus, pullSecrets []api.Secret, backOff *flowcontrol.Backoff) PodSyncResult
  74. // KillPod kills all the containers of a pod. Pod may be nil, running pod must not be.
  75. // TODO(random-liu): Return PodSyncResult in KillPod.
  76. // gracePeriodOverride if specified allows the caller to override the pod default grace period.
  77. // only hard kill paths are allowed to specify a gracePeriodOverride in the kubelet in order to not corrupt user data.
  78. // it is useful when doing SIGKILL for hard eviction scenarios, or max grace period during soft eviction scenarios.
  79. KillPod(pod *api.Pod, runningPod Pod, gracePeriodOverride *int64) error
  80. // GetPodStatus retrieves the status of the pod, including the
  81. // information of all containers in the pod that are visble in Runtime.
  82. GetPodStatus(uid types.UID, name, namespace string) (*PodStatus, error)
  83. // PullImage pulls an image from the network to local storage using the supplied
  84. // secrets if necessary.
  85. PullImage(image ImageSpec, pullSecrets []api.Secret) error
  86. // IsImagePresent checks whether the container image is already in the local storage.
  87. IsImagePresent(image ImageSpec) (bool, error)
  88. // Gets all images currently on the machine.
  89. ListImages() ([]Image, error)
  90. // Removes the specified image.
  91. RemoveImage(image ImageSpec) error
  92. // Returns Image statistics.
  93. ImageStats() (*ImageStats, error)
  94. // Returns the filesystem path of the pod's network namespace; if the
  95. // runtime does not handle namespace creation itself, or cannot return
  96. // the network namespace path, it should return an error.
  97. // TODO: Change ContainerID to a Pod ID since the namespace is shared
  98. // by all containers in the pod.
  99. GetNetNS(containerID ContainerID) (string, error)
  100. // Returns the container ID that represents the Pod, as passed to network
  101. // plugins. For example, if the runtime uses an infra container, returns
  102. // the infra container's ContainerID.
  103. // TODO: Change ContainerID to a Pod ID, see GetNetNS()
  104. GetPodContainerID(*Pod) (ContainerID, error)
  105. // TODO(vmarmol): Unify pod and containerID args.
  106. // GetContainerLogs returns logs of a specific container. By
  107. // default, it returns a snapshot of the container log. Set 'follow' to true to
  108. // stream the log. Set 'follow' to false and specify the number of lines (e.g.
  109. // "100" or "all") to tail the log.
  110. GetContainerLogs(pod *api.Pod, containerID ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) (err error)
  111. // Delete a container. If the container is still running, an error is returned.
  112. DeleteContainer(containerID ContainerID) error
  113. // ContainerCommandRunner encapsulates the command runner interfaces for testability.
  114. ContainerCommandRunner
  115. // ContainerAttach encapsulates the attaching to containers for testability
  116. ContainerAttacher
  117. }
  118. type ContainerAttacher interface {
  119. AttachContainer(id ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) (err error)
  120. }
  121. // CommandRunner encapsulates the command runner interfaces for testability.
  122. type ContainerCommandRunner interface {
  123. // Runs the command in the container of the specified pod using nsenter.
  124. // Attaches the processes stdin, stdout, and stderr. Optionally uses a
  125. // tty.
  126. ExecInContainer(containerID ContainerID, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error
  127. // Forward the specified port from the specified pod to the stream.
  128. PortForward(pod *Pod, port uint16, stream io.ReadWriteCloser) error
  129. }
  130. // Pod is a group of containers.
  131. type Pod struct {
  132. // The ID of the pod, which can be used to retrieve a particular pod
  133. // from the pod list returned by GetPods().
  134. ID types.UID
  135. // The name and namespace of the pod, which is readable by human.
  136. Name string
  137. Namespace string
  138. // List of containers that belongs to this pod. It may contain only
  139. // running containers, or mixed with dead ones (when GetPods(true)).
  140. Containers []*Container
  141. }
  142. // PodPair contains both runtime#Pod and api#Pod
  143. type PodPair struct {
  144. // APIPod is the api.Pod
  145. APIPod *api.Pod
  146. // RunningPod is the pod defined defined in pkg/kubelet/container/runtime#Pod
  147. RunningPod *Pod
  148. }
  149. // ContainerID is a type that identifies a container.
  150. type ContainerID struct {
  151. // The type of the container runtime. e.g. 'docker', 'rkt'.
  152. Type string
  153. // The identification of the container, this is comsumable by
  154. // the underlying container runtime. (Note that the container
  155. // runtime interface still takes the whole struct as input).
  156. ID string
  157. }
  158. func BuildContainerID(typ, ID string) ContainerID {
  159. return ContainerID{Type: typ, ID: ID}
  160. }
  161. // Convenience method for creating a ContainerID from an ID string.
  162. func ParseContainerID(containerID string) ContainerID {
  163. var id ContainerID
  164. if err := id.ParseString(containerID); err != nil {
  165. glog.Error(err)
  166. }
  167. return id
  168. }
  169. func (c *ContainerID) ParseString(data string) error {
  170. // Trim the quotes and split the type and ID.
  171. parts := strings.Split(strings.Trim(data, "\""), "://")
  172. if len(parts) != 2 {
  173. return fmt.Errorf("invalid container ID: %q", data)
  174. }
  175. c.Type, c.ID = parts[0], parts[1]
  176. return nil
  177. }
  178. func (c *ContainerID) String() string {
  179. return fmt.Sprintf("%s://%s", c.Type, c.ID)
  180. }
  181. func (c *ContainerID) IsEmpty() bool {
  182. return *c == ContainerID{}
  183. }
  184. func (c *ContainerID) MarshalJSON() ([]byte, error) {
  185. return []byte(fmt.Sprintf("%q", c.String())), nil
  186. }
  187. func (c *ContainerID) UnmarshalJSON(data []byte) error {
  188. return c.ParseString(string(data))
  189. }
  190. // DockerID is an ID of docker container. It is a type to make it clear when we're working with docker container Ids
  191. type DockerID string
  192. func (id DockerID) ContainerID() ContainerID {
  193. return ContainerID{
  194. Type: "docker",
  195. ID: string(id),
  196. }
  197. }
  198. type ContainerState string
  199. const (
  200. ContainerStateRunning ContainerState = "running"
  201. ContainerStateExited ContainerState = "exited"
  202. // This unknown encompasses all the states that we currently don't care.
  203. ContainerStateUnknown ContainerState = "unknown"
  204. // Not in use yet.
  205. ContainerStateCreated ContainerState = "created"
  206. )
  207. // Container provides the runtime information for a container, such as ID, hash,
  208. // state of the container.
  209. type Container struct {
  210. // The ID of the container, used by the container runtime to identify
  211. // a container.
  212. ID ContainerID
  213. // The name of the container, which should be the same as specified by
  214. // api.Container.
  215. Name string
  216. // The image name of the container, this also includes the tag of the image,
  217. // the expected form is "NAME:TAG".
  218. Image string
  219. // The id of the image used by the container.
  220. ImageID string
  221. // Hash of the container, used for comparison. Optional for containers
  222. // not managed by kubelet.
  223. Hash uint64
  224. // State is the state of the container.
  225. State ContainerState
  226. }
  227. // PodStatus represents the status of the pod and its containers.
  228. // api.PodStatus can be derived from examining PodStatus and api.Pod.
  229. type PodStatus struct {
  230. // ID of the pod.
  231. ID types.UID
  232. // Name of the pod.
  233. Name string
  234. // Namspace of the pod.
  235. Namespace string
  236. // IP of the pod.
  237. IP string
  238. // Status of containers in the pod.
  239. ContainerStatuses []*ContainerStatus
  240. }
  241. // ContainerStatus represents the status of a container.
  242. type ContainerStatus struct {
  243. // ID of the container.
  244. ID ContainerID
  245. // Name of the container.
  246. Name string
  247. // Status of the container.
  248. State ContainerState
  249. // Creation time of the container.
  250. CreatedAt time.Time
  251. // Start time of the container.
  252. StartedAt time.Time
  253. // Finish time of the container.
  254. FinishedAt time.Time
  255. // Exit code of the container.
  256. ExitCode int
  257. // Name of the image, this also includes the tag of the image,
  258. // the expected form is "NAME:TAG".
  259. Image string
  260. // ID of the image.
  261. ImageID string
  262. // Hash of the container, used for comparison.
  263. Hash uint64
  264. // Number of times that the container has been restarted.
  265. RestartCount int
  266. // A string explains why container is in such a status.
  267. Reason string
  268. // Message written by the container before exiting (stored in
  269. // TerminationMessagePath).
  270. Message string
  271. }
  272. // FindContainerStatusByName returns container status in the pod status with the given name.
  273. // When there are multiple containers' statuses with the same name, the first match will be returned.
  274. func (podStatus *PodStatus) FindContainerStatusByName(containerName string) *ContainerStatus {
  275. for _, containerStatus := range podStatus.ContainerStatuses {
  276. if containerStatus.Name == containerName {
  277. return containerStatus
  278. }
  279. }
  280. return nil
  281. }
  282. // Get container status of all the running containers in a pod
  283. func (podStatus *PodStatus) GetRunningContainerStatuses() []*ContainerStatus {
  284. runnningContainerStatues := []*ContainerStatus{}
  285. for _, containerStatus := range podStatus.ContainerStatuses {
  286. if containerStatus.State == ContainerStateRunning {
  287. runnningContainerStatues = append(runnningContainerStatues, containerStatus)
  288. }
  289. }
  290. return runnningContainerStatues
  291. }
  292. // Basic information about a container image.
  293. type Image struct {
  294. // ID of the image.
  295. ID string
  296. // Other names by which this image is known.
  297. RepoTags []string
  298. // Digests by which this image is known.
  299. RepoDigests []string
  300. // The size of the image in bytes.
  301. Size int64
  302. }
  303. type EnvVar struct {
  304. Name string
  305. Value string
  306. }
  307. type Mount struct {
  308. // Name of the volume mount.
  309. // TODO(yifan): Remove this field, as this is not representing the unique name of the mount,
  310. // but the volume name only.
  311. Name string
  312. // Path of the mount within the container.
  313. ContainerPath string
  314. // Path of the mount on the host.
  315. HostPath string
  316. // Whether the mount is read-only.
  317. ReadOnly bool
  318. // Whether the mount needs SELinux relabeling
  319. SELinuxRelabel bool
  320. }
  321. type PortMapping struct {
  322. // Name of the port mapping
  323. Name string
  324. // Protocol of the port mapping.
  325. Protocol api.Protocol
  326. // The port number within the container.
  327. ContainerPort int
  328. // The port number on the host.
  329. HostPort int
  330. // The host IP.
  331. HostIP string
  332. }
  333. // RunContainerOptions specify the options which are necessary for running containers
  334. type RunContainerOptions struct {
  335. // The environment variables list.
  336. Envs []EnvVar
  337. // The mounts for the containers.
  338. Mounts []Mount
  339. // The host devices mapped into the containers.
  340. Devices []string
  341. // The port mappings for the containers.
  342. PortMappings []PortMapping
  343. // If the container has specified the TerminationMessagePath, then
  344. // this directory will be used to create and mount the log file to
  345. // container.TerminationMessagePath
  346. PodContainerDir string
  347. // The list of DNS servers for the container to use.
  348. DNS []string
  349. // The list of DNS search domains.
  350. DNSSearch []string
  351. // The parent cgroup to pass to Docker
  352. CgroupParent string
  353. // The type of container rootfs
  354. ReadOnly bool
  355. // hostname for pod containers
  356. Hostname string
  357. }
  358. // VolumeInfo contains information about the volume.
  359. type VolumeInfo struct {
  360. // Mounter is the volume's mounter
  361. Mounter volume.Mounter
  362. // SELinuxLabeled indicates whether this volume has had the
  363. // pod's SELinux label applied to it or not
  364. SELinuxLabeled bool
  365. }
  366. type VolumeMap map[string]VolumeInfo
  367. type Pods []*Pod
  368. // FindPodByID finds and returns a pod in the pod list by UID. It will return an empty pod
  369. // if not found.
  370. func (p Pods) FindPodByID(podUID types.UID) Pod {
  371. for i := range p {
  372. if p[i].ID == podUID {
  373. return *p[i]
  374. }
  375. }
  376. return Pod{}
  377. }
  378. // FindPodByFullName finds and returns a pod in the pod list by the full name.
  379. // It will return an empty pod if not found.
  380. func (p Pods) FindPodByFullName(podFullName string) Pod {
  381. for i := range p {
  382. if BuildPodFullName(p[i].Name, p[i].Namespace) == podFullName {
  383. return *p[i]
  384. }
  385. }
  386. return Pod{}
  387. }
  388. // FindPod combines FindPodByID and FindPodByFullName, it finds and returns a pod in the
  389. // pod list either by the full name or the pod ID. It will return an empty pod
  390. // if not found.
  391. func (p Pods) FindPod(podFullName string, podUID types.UID) Pod {
  392. if len(podFullName) > 0 {
  393. return p.FindPodByFullName(podFullName)
  394. }
  395. return p.FindPodByID(podUID)
  396. }
  397. // FindContainerByName returns a container in the pod with the given name.
  398. // When there are multiple containers with the same name, the first match will
  399. // be returned.
  400. func (p *Pod) FindContainerByName(containerName string) *Container {
  401. for _, c := range p.Containers {
  402. if c.Name == containerName {
  403. return c
  404. }
  405. }
  406. return nil
  407. }
  408. func (p *Pod) FindContainerByID(id ContainerID) *Container {
  409. for _, c := range p.Containers {
  410. if c.ID == id {
  411. return c
  412. }
  413. }
  414. return nil
  415. }
  416. // ToAPIPod converts Pod to api.Pod. Note that if a field in api.Pod has no
  417. // corresponding field in Pod, the field would not be populated.
  418. func (p *Pod) ToAPIPod() *api.Pod {
  419. var pod api.Pod
  420. pod.UID = p.ID
  421. pod.Name = p.Name
  422. pod.Namespace = p.Namespace
  423. for _, c := range p.Containers {
  424. var container api.Container
  425. container.Name = c.Name
  426. container.Image = c.Image
  427. pod.Spec.Containers = append(pod.Spec.Containers, container)
  428. }
  429. return &pod
  430. }
  431. // IsEmpty returns true if the pod is empty.
  432. func (p *Pod) IsEmpty() bool {
  433. return reflect.DeepEqual(p, &Pod{})
  434. }
  435. // GetPodFullName returns a name that uniquely identifies a pod.
  436. func GetPodFullName(pod *api.Pod) string {
  437. // Use underscore as the delimiter because it is not allowed in pod name
  438. // (DNS subdomain format), while allowed in the container name format.
  439. return pod.Name + "_" + pod.Namespace
  440. }
  441. // Build the pod full name from pod name and namespace.
  442. func BuildPodFullName(name, namespace string) string {
  443. return name + "_" + namespace
  444. }
  445. // Parse the pod full name.
  446. func ParsePodFullName(podFullName string) (string, string, error) {
  447. parts := strings.Split(podFullName, "_")
  448. if len(parts) != 2 {
  449. return "", "", fmt.Errorf("failed to parse the pod full name %q", podFullName)
  450. }
  451. return parts[0], parts[1], nil
  452. }
  453. // Option is a functional option type for Runtime, useful for
  454. // completely optional settings.
  455. type Option func(Runtime)
  456. // Sort the container statuses by creation time.
  457. type SortContainerStatusesByCreationTime []*ContainerStatus
  458. func (s SortContainerStatusesByCreationTime) Len() int { return len(s) }
  459. func (s SortContainerStatusesByCreationTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  460. func (s SortContainerStatusesByCreationTime) Less(i, j int) bool {
  461. return s[i].CreatedAt.Before(s[j].CreatedAt)
  462. }