Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding per container stats for CRI runtimes #59906

Merged
merged 2 commits into from
Feb 22, 2018

Conversation

abhi
Copy link
Contributor

@abhi abhi commented Feb 15, 2018

For kubernetes/enhancements#552.

What this PR does / why we need it

This commit aims to collect per container log stats. The change was proposed as a part of #55905. The change includes change the log path from /var/pod//containername_attempt.log to /var/pod//containername/containername_attempt.log. The logs are collected by reusing volume package to collect metrics from the log path.
Fixes #55905

Special notes for your reviewer:
cc @Random-Liu

Release note:

Adding container log stats for CRI runtimes.

@k8s-ci-robot
Copy link
Contributor

@abhi: Adding do-not-merge/release-note-label-needed because the release note process has not been followed.

One of the following labels is required "release-note", "release-note-action-required", or "release-note-none".
Please see: https://git.k8s.io/community/contributors/devel/pull-requests.md#write-release-notes-if-needed.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Feb 15, 2018
@abhi abhi force-pushed the log_stats branch 2 times, most recently from 4674aa7 to 344721a Compare February 15, 2018 06:10
@Random-Liu Random-Liu added this to the v1.10 milestone Feb 15, 2018
@Random-Liu Random-Liu self-assigned this Feb 15, 2018
@Random-Liu Random-Liu added release-note Denotes a PR that will be considered when it comes time to generate release notes. area/monitoring sig/node Categorizes an issue or PR as relevant to SIG Node. and removed do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Feb 15, 2018
@@ -207,14 +207,19 @@ func getStableKey(pod *v1.Pod, container *v1.Container) string {

// buildContainerLogsPath builds log path for container relative to pod logs directory.
func buildContainerLogsPath(containerName string, restartCount int) string {
return fmt.Sprintf("%s_%d.log", containerName, restartCount)
return fmt.Sprintf("%s/%s_%d.log", containerName, containerName, restartCount)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we can use restartCount as log file name for now until we have more metadata to add. Just to make the path shorter.
@mrunalp @feiskyer WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -207,14 +207,19 @@ func getStableKey(pod *v1.Pod, container *v1.Container) string {

// buildContainerLogsPath builds log path for container relative to pod logs directory.
func buildContainerLogsPath(containerName string, restartCount int) string {
return fmt.Sprintf("%s_%d.log", containerName, restartCount)
return fmt.Sprintf("%s/%s_%d.log", containerName, containerName, restartCount)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep consistent filepath.Join

@@ -190,6 +190,11 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *v1.Contai
}

command, args := kubecontainer.ExpandContainerCommandAndArgs(container, opts.Envs)
logDir := fmt.Sprintf("%s/%s", buildPodLogsDirectory(pod.UID), container.Name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use your helper function. BuildContainerLogsDirectory

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this directory when remove container.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. Will do

@@ -61,7 +61,7 @@ func TestRemoveContainer(t *testing.T) {
err = m.removeContainer(containerId)
assert.NoError(t, err)
// Verify container log is removed
expectedContainerLogPath := filepath.Join(podLogsRootDirectory, "12345678", "foo_0.log")
expectedContainerLogPath := filepath.Join(podLogsRootDirectory, "12345678", "/foo/foo_0.log")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Join instead of /.

"foo", "0.log"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

m := volume.NewMetricsDu(path)
logMetrics, err := m.GetMetrics()
if err != nil {
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log the error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -423,3 +415,26 @@ func getCRICadvisorStats(ca cadvisor.Interface) (map[string]cadvisorapiv2.Contai
}
return stats, nil
}

func getContainerLogStats(path string) *statsapi.FsStats {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add TODO, cache this in container log manager.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


func makeFakeLogs(sandbox *critest.FakePodSandbox, containers ...string) {
for _, name := range containers {
os.MkdirAll(fmt.Sprintf("/var/log/pods/%s/%s/", types.UID(sandbox.GetMetadata().GetUid()), name), 755)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use your helper function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

func deleteFakeLogs(sandbox *critest.FakePodSandbox) {
os.RemoveAll(fmt.Sprintf("/var/log/pods/%s", types.UID(sandbox.GetMetadata().GetUid())))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed


func makeFakeLogs(sandbox *critest.FakePodSandbox, containers ...string) {
for _, name := range containers {
os.MkdirAll(fmt.Sprintf("/var/log/pods/%s/%s/", types.UID(sandbox.GetMetadata().GetUid()), name), 755)
Copy link
Member

@Random-Liu Random-Liu Feb 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/var/log/pods is actual pod/container log directory. We should not create files there in unit test... We may ruin people's local environment...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep went mock approach

@@ -423,3 +415,26 @@ func getCRICadvisorStats(ca cadvisor.Interface) (map[string]cadvisorapiv2.Contai
}
return stats, nil
}

func getContainerLogStats(path string) *statsapi.FsStats {
m := volume.NewMetricsDu(path)
Copy link
Member

@Random-Liu Random-Liu Feb 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NewMetricsDu returns an interface MetricsProvider. It should be easy to mock.
Let's use a mock instead of using actual log stats.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@abhi
Copy link
Contributor Author

abhi commented Feb 16, 2018

@Random-Liu will update the PR and address the review comments. Thanks for reviewing

@k8s-ci-robot
Copy link
Contributor

@abhi: Adding do-not-merge/release-note-label-needed because the release note process has not been followed.

One of the following labels is required "release-note", "release-note-action-required", or "release-note-none".
Please see: https://git.k8s.io/community/contributors/devel/pull-requests.md#write-release-notes-if-needed.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. and removed release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Feb 17, 2018
@abhi abhi force-pushed the log_stats branch 2 times, most recently from 820c3ed to 24a2d33 Compare February 17, 2018 22:45
@Random-Liu Random-Liu added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Feb 21, 2018
assert.Equal(*rootFsInfo.Inodes, *actual.Logs.Inodes)
assert.Nil(actual.Logs.UsedBytes)
assert.Nil(actual.Logs.InodesUsed)
func checkCRILogsStats(assert *assert.Assertions, actual statsapi.ContainerStats) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compare the value for rootFsInfo and log stats. That's the point of the fake, right? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


func makeFakeLogStats(seed int) *volume.Metrics {
m := &volume.Metrics{}
m.Used = resource.NewQuantity(int64(0), resource.BinarySI) //seed + offsetUsage),resource.BinarySI)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? comment not removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -190,6 +190,11 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *v1.Contai
}

command, args := kubecontainer.ExpandContainerCommandAndArgs(container, opts.Envs)
logDir := BuildContainerLogsDirectory(kubetypes.UID(pod.UID), container.Name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the directory in removeContainerLog

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

This commit aims to collect per container log stats. The
change was proposed as a part of kubernetes#55905. The change includes
change of the log path from /var/pod/<pod uid>/containername_attempt.log
to /var/pod/<pod uid>/containername/containername_attempt.log.
The logs are collected by reusing volume package to collect
metrics from the log path.

Signed-off-by: abhi <abhi@docker.com>
@abhi abhi force-pushed the log_stats branch 3 times, most recently from 7f861d4 to 42b9205 Compare February 21, 2018 06:12
@@ -840,8 +845,7 @@ func (m *kubeGenericRuntimeManager) removeContainerLog(containerID string) error
return fmt.Errorf("failed to get container status %q: %v", containerID, err)
}
labeledInfo := getContainerInfoFromLabels(status.Labels)
annotatedInfo := getContainerInfoFromAnnotations(status.Annotations)
path := buildFullContainerLogsPath(labeledInfo.PodUID, labeledInfo.ContainerName, annotatedInfo.RestartCount)
path := BuildContainerLogsDirectory(labeledInfo.PodUID, labeledInfo.ContainerName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry... This is my fault... We can't remove the whole directory... There might be newer instance of container log with different restart count in this directory. Let's leave the container log directory to be deleted when pod deletion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep :) Cool will update

The commit contains test case modifications to test
and verify changes for container log stats feature.

Signed-off-by: abhi <abhi@docker.com>
@Random-Liu
Copy link
Member

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 21, 2018
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: abhi, Random-Liu

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 21, 2018
Copy link
Member

@feiskyer feiskyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the change is not tied to any platform, volume.MetricsProvider doesn't support windows yet. Will open a new issue for windows.

LGTM

@k8s-github-robot
Copy link

Automatic merge from submit-queue (batch tested with PRs 54191, 59374, 59824, 55032, 59906). If you want to cherry-pick this change to another branch, please follow the instructions here.

@k8s-github-robot k8s-github-robot merged commit 742c9b1 into kubernetes:master Feb 22, 2018
@k8s-ci-robot
Copy link
Contributor

@abhi: Adding do-not-merge/release-note-label-needed because the release note process has not been followed.

One of the following labels is required "release-note", "release-note-action-required", or "release-note-none".
Please see: https://git.k8s.io/community/contributors/devel/pull-requests.md#write-release-notes-if-needed.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. and removed release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Feb 27, 2018
k8s-github-robot pushed a commit that referenced this pull request May 15, 2018
Automatic merge from submit-queue (batch tested with PRs 63603, 63557, 62015). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

CRI: update documents for container logpath

**What this PR does / why we need it**:

The container log path has been changed from  `containername_attempt#.log` to `containername/attempt#.log` in #59906. This PR updates CRI documents for it.

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #

**Special notes for your reviewer**:

**Release note**:

```release-note
CRI: update documents for container logpath. The container log path has been changed from containername_attempt#.log to containername/attempt#.log 
```
@andor44
Copy link

andor44 commented Jul 11, 2018

This change broke retrieval of logs for pods that were started on a <1.10 cluster that got upgraded to 1.10, even though this has nothing to do with CRI:

k logs -f <foo>
failed to open log file "/var/log/pods/<UUID>/<container name>/<restart count>.log": open /var/log/pods/<UUID>/<container name>/<restart count>.log: no such file or directory

I'm sorry for the bluntness but how the hell can such a change get merged without any regard for backwards compatibility?

@Random-Liu
Copy link
Member

@andor44 Are you using cri-o?

@andor44
Copy link

andor44 commented Jul 11, 2018

No, Docker 1.12. I worded my original comment wrongly, by "has nothing to do with CRI" I meant we don't use a CRI runtime.

@Random-Liu
Copy link
Member

Random-Liu commented Jul 11, 2018

@andor44
We made a change to avoid the backward compatibility issue, but that was only in 1.11 #63268.

When upgrading from 1.9 to 1.10, you will have this issue. I'll say this is expected, because:

  1. We never officially support in-place Kubelet update, it is always recommended to drain the node first before upgrade.
  2. CRI had a breaking change, and the log path change is one of the breaking changes. The CRI version is also bumped up to v1alpha2 in 1.10. https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.10.md#before-upgrading

We can cherry-pick #63268 to 1.10 for this, because the fix is small. @yujuhong Are you ok with that?

But please note that in-place kubelet may break again in the future, because it is never supported. :)

@yujuhong
Copy link
Contributor

We can cherry-pick #63268 to 1.10 for this, because the fix is small. @yujuhong Are you ok with that?

Sounds good.

@feiskyer
Copy link
Member

We can cherry-pick #63268 to 1.10 for this, because the fix is small.

LGTM. Created #66096 for this.

@andor44
Copy link

andor44 commented Jul 12, 2018

@Random-Liu understandable, but it seems that point 1 is undocumented, or at least I can't find anything in the docs that would indicate that the kubelet does not support in-place upgrades. I know that a lack of warning does not indicate support, but lots of online guides and how-tos tell you to do just that. Given that other components deal with in-place upgrades just fine, it is not a big mental leap to assume kubelet does too. If the kubelet really doesn't support it and such breaks are to be expected it should be well documented IMO.

FWIW, the cluster in question has been upgraded from 1.5 all the way to 1.10 over the past 2 years or so, and this is the first time we ran into some serious incompatibility/issue.

@lucaim
Copy link

lucaim commented Jul 12, 2018

I have to say that I agree with @andor44 here. We probably made assumption based, at least partially, on the lack of documentation or the presence of the contrary and our experience related to that. I knew that on GKE for example the node is drained but this could have been for a cloud specific issue/best practice. For us, on bare metal, it worked all the times. I kindly suggest to explicitly put this in the documentation. Thanks for the effort done in cherry picking the fix.

@Random-Liu
Copy link
Member

@andor44 @lucaim For this particular issue, we should mention it in the BeforeUpgrade, which we should start doing for CRI changes. @yujuhong @feiskyer

@yujuhong
Copy link
Contributor

@andor44 @lucaim I agree that the release note should call out issues that may lead to container restarts (or other problems among kubelet upgrade) if possible. This is our oversight and sorry for the trouble.

AFAIK, the kubelet in-place upgrade path is not tested, so these issues may not be caught and well-documented before release. Just like the stackoverflow question @andor44 mentioned, container restarts also happened in 1.7 to 1.8 upgrade as well. If you use pod manifest files on the node, they'd encounter upgrade issues even more frequently (arguably by design). Given the current situation, I'd recommend draining the node to avoid unexpected issues.

@feiskyer
Copy link
Member

Agreed. Since this particular issue has been mitigated, let's address those user-facing issues clearly in the future on both PR's changelog and BeforeUpgrade part.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/monitoring cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. lgtm "Looks good to me", indicates that a PR is ready to be merged. sig/node Categorizes an issue or PR as relevant to SIG Node. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants