Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
121a91eb
Commit
121a91eb
authored
Oct 14, 2016
by
Random-Liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Symlink docker logs to CRI defined log path.
parent
a7db9bcc
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
382 additions
and
36 deletions
+382
-36
fake_runtime_service.go
pkg/kubelet/api/testing/fake_runtime_service.go
+11
-0
os.go
pkg/kubelet/container/os.go
+6
-0
os.go
pkg/kubelet/container/testing/os.go
+21
-8
docker_container.go
pkg/kubelet/dockershim/docker_container.go
+71
-2
docker_container_test.go
pkg/kubelet/dockershim/docker_container_test.go
+44
-0
docker_sandbox.go
pkg/kubelet/dockershim/docker_sandbox.go
+1
-1
docker_service.go
pkg/kubelet/dockershim/docker_service.go
+4
-1
docker_service_test.go
pkg/kubelet/dockershim/docker_service_test.go
+2
-1
helpers.go
pkg/kubelet/kuberuntime/helpers.go
+12
-0
kuberuntime_container.go
pkg/kubelet/kuberuntime/kuberuntime_container.go
+33
-9
kuberuntime_container_test.go
pkg/kubelet/kuberuntime/kuberuntime_container_test.go
+66
-0
kuberuntime_gc.go
pkg/kubelet/kuberuntime/kuberuntime_gc.go
+36
-14
kuberuntime_sandbox.go
pkg/kubelet/kuberuntime/kuberuntime_sandbox.go
+11
-0
kuberuntime_sandbox_test.go
pkg/kubelet/kuberuntime/kuberuntime_sandbox_test.go
+64
-0
No files found.
pkg/kubelet/api/testing/fake_runtime_service.go
View file @
121a91eb
...
@@ -19,6 +19,7 @@ package testing
...
@@ -19,6 +19,7 @@ package testing
import
(
import
(
"fmt"
"fmt"
"io"
"io"
"reflect"
"sync"
"sync"
"time"
"time"
...
@@ -77,6 +78,16 @@ func (r *FakeRuntimeService) SetFakeContainers(containers []*FakeContainer) {
...
@@ -77,6 +78,16 @@ func (r *FakeRuntimeService) SetFakeContainers(containers []*FakeContainer) {
}
}
func
(
r
*
FakeRuntimeService
)
AssertCalls
(
calls
[]
string
)
error
{
r
.
Lock
()
defer
r
.
Unlock
()
if
!
reflect
.
DeepEqual
(
calls
,
r
.
Called
)
{
return
fmt
.
Errorf
(
"expected %#v, got %#v"
,
calls
,
r
.
Called
)
}
return
nil
}
func
NewFakeRuntimeService
()
*
FakeRuntimeService
{
func
NewFakeRuntimeService
()
*
FakeRuntimeService
{
return
&
FakeRuntimeService
{
return
&
FakeRuntimeService
{
Called
:
make
([]
string
,
0
),
Called
:
make
([]
string
,
0
),
...
...
pkg/kubelet/container/os.go
View file @
121a91eb
...
@@ -29,6 +29,7 @@ type OSInterface interface {
...
@@ -29,6 +29,7 @@ type OSInterface interface {
Symlink
(
oldname
string
,
newname
string
)
error
Symlink
(
oldname
string
,
newname
string
)
error
Stat
(
path
string
)
(
os
.
FileInfo
,
error
)
Stat
(
path
string
)
(
os
.
FileInfo
,
error
)
Remove
(
path
string
)
error
Remove
(
path
string
)
error
RemoveAll
(
path
string
)
error
Create
(
path
string
)
(
*
os
.
File
,
error
)
Create
(
path
string
)
(
*
os
.
File
,
error
)
Hostname
()
(
name
string
,
err
error
)
Hostname
()
(
name
string
,
err
error
)
Chtimes
(
path
string
,
atime
time
.
Time
,
mtime
time
.
Time
)
error
Chtimes
(
path
string
,
atime
time
.
Time
,
mtime
time
.
Time
)
error
...
@@ -59,6 +60,11 @@ func (RealOS) Remove(path string) error {
...
@@ -59,6 +60,11 @@ func (RealOS) Remove(path string) error {
return
os
.
Remove
(
path
)
return
os
.
Remove
(
path
)
}
}
// RemoveAll will call os.RemoveAll to remove the path and its children.
func
(
RealOS
)
RemoveAll
(
path
string
)
error
{
return
os
.
RemoveAll
(
path
)
}
// Create will call os.Create to create and return a file
// Create will call os.Create to create and return a file
// at path.
// at path.
func
(
RealOS
)
Create
(
path
string
)
(
*
os
.
File
,
error
)
{
func
(
RealOS
)
Create
(
path
string
)
(
*
os
.
File
,
error
)
{
...
...
pkg/kubelet/container/testing/os.go
View file @
121a91eb
...
@@ -26,11 +26,13 @@ import (
...
@@ -26,11 +26,13 @@ import (
// If a member of the form `*Fn` is set, that function will be called in place
// If a member of the form `*Fn` is set, that function will be called in place
// of the real call.
// of the real call.
type
FakeOS
struct
{
type
FakeOS
struct
{
StatFn
func
(
string
)
(
os
.
FileInfo
,
error
)
StatFn
func
(
string
)
(
os
.
FileInfo
,
error
)
ReadDirFn
func
(
string
)
([]
os
.
FileInfo
,
error
)
ReadDirFn
func
(
string
)
([]
os
.
FileInfo
,
error
)
HostName
string
MkdirAllFn
func
(
string
,
os
.
FileMode
)
error
Removes
[]
string
SymlinkFn
func
(
string
,
string
)
error
Files
map
[
string
][]
*
os
.
FileInfo
HostName
string
Removes
[]
string
Files
map
[
string
][]
*
os
.
FileInfo
}
}
func
NewFakeOS
()
*
FakeOS
{
func
NewFakeOS
()
*
FakeOS
{
...
@@ -41,12 +43,18 @@ func NewFakeOS() *FakeOS {
...
@@ -41,12 +43,18 @@ func NewFakeOS() *FakeOS {
}
}
// Mkdir is a fake call that just returns nil.
// Mkdir is a fake call that just returns nil.
func
(
FakeOS
)
MkdirAll
(
path
string
,
perm
os
.
FileMode
)
error
{
func
(
f
*
FakeOS
)
MkdirAll
(
path
string
,
perm
os
.
FileMode
)
error
{
if
f
.
MkdirAllFn
!=
nil
{
return
f
.
MkdirAllFn
(
path
,
perm
)
}
return
nil
return
nil
}
}
// Symlink is a fake call that just returns nil.
// Symlink is a fake call that just returns nil.
func
(
FakeOS
)
Symlink
(
oldname
string
,
newname
string
)
error
{
func
(
f
*
FakeOS
)
Symlink
(
oldname
string
,
newname
string
)
error
{
if
f
.
SymlinkFn
!=
nil
{
return
f
.
SymlinkFn
(
oldname
,
newname
)
}
return
nil
return
nil
}
}
...
@@ -64,6 +72,11 @@ func (f *FakeOS) Remove(path string) error {
...
@@ -64,6 +72,11 @@ func (f *FakeOS) Remove(path string) error {
return
nil
return
nil
}
}
// RemoveAll is a fake call that just returns nil.
func
(
f
*
FakeOS
)
RemoveAll
(
path
string
)
error
{
return
nil
}
// Create is a fake call that returns nil.
// Create is a fake call that returns nil.
func
(
FakeOS
)
Create
(
path
string
)
(
*
os
.
File
,
error
)
{
func
(
FakeOS
)
Create
(
path
string
)
(
*
os
.
File
,
error
)
{
return
nil
,
nil
return
nil
,
nil
...
@@ -89,5 +102,5 @@ func (f *FakeOS) ReadDir(dirname string) ([]os.FileInfo, error) {
...
@@ -89,5 +102,5 @@ func (f *FakeOS) ReadDir(dirname string) ([]os.FileInfo, error) {
if
f
.
ReadDirFn
!=
nil
{
if
f
.
ReadDirFn
!=
nil
{
return
f
.
ReadDirFn
(
dirname
)
return
f
.
ReadDirFn
(
dirname
)
}
}
return
nil
,
errors
.
New
(
"unimplemented testing mock"
)
return
nil
,
nil
}
}
pkg/kubelet/dockershim/docker_container.go
View file @
121a91eb
...
@@ -19,6 +19,8 @@ package dockershim
...
@@ -19,6 +19,8 @@ package dockershim
import
(
import
(
"fmt"
"fmt"
"io"
"io"
"os"
"path/filepath"
"time"
"time"
dockertypes
"github.com/docker/engine-api/types"
dockertypes
"github.com/docker/engine-api/types"
...
@@ -91,6 +93,8 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
...
@@ -91,6 +93,8 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
labels
:=
makeLabels
(
config
.
GetLabels
(),
config
.
GetAnnotations
())
labels
:=
makeLabels
(
config
.
GetLabels
(),
config
.
GetAnnotations
())
// Apply a the container type label.
// Apply a the container type label.
labels
[
containerTypeLabelKey
]
=
containerTypeLabelContainer
labels
[
containerTypeLabelKey
]
=
containerTypeLabelContainer
// Write the container log path in the labels.
labels
[
containerLogPathLabelKey
]
=
filepath
.
Join
(
sandboxConfig
.
GetLogDirectory
(),
config
.
GetLogPath
())
// Write the sandbox ID in the labels.
// Write the sandbox ID in the labels.
labels
[
sandboxIDLabelKey
]
=
podSandboxID
labels
[
sandboxIDLabelKey
]
=
podSandboxID
...
@@ -181,9 +185,63 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
...
@@ -181,9 +185,63 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
return
""
,
err
return
""
,
err
}
}
// getContainerLogPath returns the container log path specified by kubelet and the real
// path where docker stores the container log.
func
(
ds
*
dockerService
)
getContainerLogPath
(
containerID
string
)
(
string
,
string
,
error
)
{
info
,
err
:=
ds
.
client
.
InspectContainer
(
containerID
)
if
err
!=
nil
{
return
""
,
""
,
fmt
.
Errorf
(
"failed to inspect container %q: %v"
,
containerID
,
err
)
}
return
info
.
Config
.
Labels
[
containerLogPathLabelKey
],
info
.
LogPath
,
nil
}
// createContainerLogSymlink creates the symlink for docker container log.
func
(
ds
*
dockerService
)
createContainerLogSymlink
(
containerID
string
)
error
{
path
,
realPath
,
err
:=
ds
.
getContainerLogPath
(
containerID
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to get container %q log path: %v"
,
containerID
,
err
)
}
if
path
!=
""
{
// Only create the symlink when container log path is specified.
if
err
=
ds
.
os
.
Symlink
(
realPath
,
path
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to create symbolic link %q to the container log file %q for container %q: %v"
,
path
,
realPath
,
containerID
,
err
)
}
}
return
nil
}
// removeContainerLogSymlink removes the symlink for docker container log.
func
(
ds
*
dockerService
)
removeContainerLogSymlink
(
containerID
string
)
error
{
path
,
_
,
err
:=
ds
.
getContainerLogPath
(
containerID
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to get container %q log path: %v"
,
containerID
,
err
)
}
if
path
!=
""
{
// Only remove the symlink when container log path is specified.
err
:=
ds
.
os
.
Remove
(
path
)
if
err
!=
nil
&&
!
os
.
IsNotExist
(
err
)
{
return
fmt
.
Errorf
(
"failed to remove container %q log symlink %q: %v"
,
containerID
,
path
,
err
)
}
}
return
nil
}
// StartContainer starts the container.
// StartContainer starts the container.
func
(
ds
*
dockerService
)
StartContainer
(
containerID
string
)
error
{
func
(
ds
*
dockerService
)
StartContainer
(
containerID
string
)
error
{
return
ds
.
client
.
StartContainer
(
containerID
)
err
:=
ds
.
client
.
StartContainer
(
containerID
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to start container %q: %v"
,
containerID
,
err
)
}
// Create container log symlink.
if
err
:=
ds
.
createContainerLogSymlink
(
containerID
);
err
!=
nil
{
// Do not stop the container if fail to create symlink, because:
// 1. This is not a critical failure.
// 2. We don't have enough information to properly stop container here.
// Kubelet will surface this error to user with event.
return
err
}
return
nil
}
}
// StopContainer stops a running container with a grace period (i.e., timeout).
// StopContainer stops a running container with a grace period (i.e., timeout).
...
@@ -194,7 +252,18 @@ func (ds *dockerService) StopContainer(containerID string, timeout int64) error
...
@@ -194,7 +252,18 @@ func (ds *dockerService) StopContainer(containerID string, timeout int64) error
// RemoveContainer removes the container.
// RemoveContainer removes the container.
// TODO: If a container is still running, should we forcibly remove it?
// TODO: If a container is still running, should we forcibly remove it?
func
(
ds
*
dockerService
)
RemoveContainer
(
containerID
string
)
error
{
func
(
ds
*
dockerService
)
RemoveContainer
(
containerID
string
)
error
{
return
ds
.
client
.
RemoveContainer
(
containerID
,
dockertypes
.
ContainerRemoveOptions
{
RemoveVolumes
:
true
})
// Ideally, log lifecycle should be independent of container lifecycle.
// However, docker will remove container log after container is removed,
// we can't prevent that now, so we also cleanup the symlink here.
err
:=
ds
.
removeContainerLogSymlink
(
containerID
)
if
err
!=
nil
{
return
err
}
err
=
ds
.
client
.
RemoveContainer
(
containerID
,
dockertypes
.
ContainerRemoveOptions
{
RemoveVolumes
:
true
})
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to remove container %q: %v"
,
containerID
,
err
)
}
return
nil
}
}
func
getContainerTimestamps
(
r
*
dockertypes
.
ContainerJSON
)
(
time
.
Time
,
time
.
Time
,
time
.
Time
,
error
)
{
func
getContainerTimestamps
(
r
*
dockertypes
.
ContainerJSON
)
(
time
.
Time
,
time
.
Time
,
time
.
Time
,
error
)
{
...
...
pkg/kubelet/dockershim/docker_container_test.go
View file @
121a91eb
...
@@ -18,12 +18,14 @@ package dockershim
...
@@ -18,12 +18,14 @@ package dockershim
import
(
import
(
"fmt"
"fmt"
"path/filepath"
"testing"
"testing"
"time"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/assert"
runtimeApi
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
runtimeApi
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
containertest
"k8s.io/kubernetes/pkg/kubelet/container/testing"
)
)
// A helper to create a basic config.
// A helper to create a basic config.
...
@@ -171,3 +173,45 @@ func TestContainerStatus(t *testing.T) {
...
@@ -171,3 +173,45 @@ func TestContainerStatus(t *testing.T) {
status
,
err
=
ds
.
ContainerStatus
(
id
)
status
,
err
=
ds
.
ContainerStatus
(
id
)
assert
.
Error
(
t
,
err
,
fmt
.
Sprintf
(
"status of container: %+v"
,
status
))
assert
.
Error
(
t
,
err
,
fmt
.
Sprintf
(
"status of container: %+v"
,
status
))
}
}
// TestContainerLogPath tests the container log creation logic.
func
TestContainerLogPath
(
t
*
testing
.
T
)
{
ds
,
fDocker
,
_
:=
newTestDockerService
()
podLogPath
:=
"/pod/1"
containerLogPath
:=
"0"
kubeletContainerLogPath
:=
filepath
.
Join
(
podLogPath
,
containerLogPath
)
sConfig
:=
makeSandboxConfig
(
"foo"
,
"bar"
,
"1"
,
0
)
sConfig
.
LogDirectory
=
&
podLogPath
config
:=
makeContainerConfig
(
sConfig
,
"pause"
,
"iamimage"
,
0
,
nil
,
nil
)
config
.
LogPath
=
&
containerLogPath
const
sandboxId
=
"sandboxid"
id
,
err
:=
ds
.
CreateContainer
(
sandboxId
,
config
,
sConfig
)
// Check internal container log label
c
,
err
:=
fDocker
.
InspectContainer
(
id
)
assert
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
c
.
Config
.
Labels
[
containerLogPathLabelKey
],
kubeletContainerLogPath
)
// Set docker container log path
dockerContainerLogPath
:=
"/docker/container/log"
c
.
LogPath
=
dockerContainerLogPath
// Verify container log symlink creation
fakeOS
:=
ds
.
os
.
(
*
containertest
.
FakeOS
)
fakeOS
.
SymlinkFn
=
func
(
oldname
,
newname
string
)
error
{
assert
.
Equal
(
t
,
dockerContainerLogPath
,
oldname
)
assert
.
Equal
(
t
,
kubeletContainerLogPath
,
newname
)
return
nil
}
err
=
ds
.
StartContainer
(
id
)
assert
.
NoError
(
t
,
err
)
err
=
ds
.
StopContainer
(
id
,
0
)
assert
.
NoError
(
t
,
err
)
// Verify container log symlink deletion
err
=
ds
.
RemoveContainer
(
id
)
assert
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
fakeOS
.
Removes
,
[]
string
{
kubeletContainerLogPath
})
}
pkg/kubelet/dockershim/docker_sandbox.go
View file @
121a91eb
...
@@ -71,7 +71,7 @@ func (ds *dockerService) RunPodSandbox(config *runtimeApi.PodSandboxConfig) (str
...
@@ -71,7 +71,7 @@ func (ds *dockerService) RunPodSandbox(config *runtimeApi.PodSandboxConfig) (str
// Step 3: Start the sandbox container.
// Step 3: Start the sandbox container.
// Assume kubelet's garbage collector would remove the sandbox later, if
// Assume kubelet's garbage collector would remove the sandbox later, if
// startContainer failed.
// startContainer failed.
err
=
ds
.
StartContainer
(
createResp
.
ID
)
err
=
ds
.
client
.
StartContainer
(
createResp
.
ID
)
return
createResp
.
ID
,
err
return
createResp
.
ID
,
err
}
}
...
...
pkg/kubelet/dockershim/docker_service.go
View file @
121a91eb
...
@@ -48,16 +48,18 @@ const (
...
@@ -48,16 +48,18 @@ const (
containerTypeLabelKey
=
"io.kubernetes.docker.type"
containerTypeLabelKey
=
"io.kubernetes.docker.type"
containerTypeLabelSandbox
=
"podsandbox"
containerTypeLabelSandbox
=
"podsandbox"
containerTypeLabelContainer
=
"container"
containerTypeLabelContainer
=
"container"
containerLogPathLabelKey
=
"io.kubernetes.container.logpath"
sandboxIDLabelKey
=
"io.kubernetes.sandbox.id"
sandboxIDLabelKey
=
"io.kubernetes.sandbox.id"
)
)
var
internalLabelKeys
[]
string
=
[]
string
{
containerTypeLabelKey
,
sandboxIDLabelKey
}
var
internalLabelKeys
[]
string
=
[]
string
{
containerTypeLabelKey
,
containerLogPathLabelKey
,
sandboxIDLabelKey
}
// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
func
NewDockerService
(
client
dockertools
.
DockerInterface
,
seccompProfileRoot
string
,
podSandboxImage
string
)
DockerLegacyService
{
func
NewDockerService
(
client
dockertools
.
DockerInterface
,
seccompProfileRoot
string
,
podSandboxImage
string
)
DockerLegacyService
{
return
&
dockerService
{
return
&
dockerService
{
seccompProfileRoot
:
seccompProfileRoot
,
seccompProfileRoot
:
seccompProfileRoot
,
client
:
dockertools
.
NewInstrumentedDockerInterface
(
client
),
client
:
dockertools
.
NewInstrumentedDockerInterface
(
client
),
os
:
kubecontainer
.
RealOS
{},
podSandboxImage
:
podSandboxImage
,
podSandboxImage
:
podSandboxImage
,
}
}
}
}
...
@@ -81,6 +83,7 @@ type DockerLegacyService interface {
...
@@ -81,6 +83,7 @@ type DockerLegacyService interface {
type
dockerService
struct
{
type
dockerService
struct
{
seccompProfileRoot
string
seccompProfileRoot
string
client
dockertools
.
DockerInterface
client
dockertools
.
DockerInterface
os
kubecontainer
.
OSInterface
podSandboxImage
string
podSandboxImage
string
}
}
...
...
pkg/kubelet/dockershim/docker_service_test.go
View file @
121a91eb
...
@@ -19,6 +19,7 @@ package dockershim
...
@@ -19,6 +19,7 @@ package dockershim
import
(
import
(
"time"
"time"
containertest
"k8s.io/kubernetes/pkg/kubelet/container/testing"
"k8s.io/kubernetes/pkg/kubelet/dockertools"
"k8s.io/kubernetes/pkg/kubelet/dockertools"
"k8s.io/kubernetes/pkg/util/clock"
"k8s.io/kubernetes/pkg/util/clock"
)
)
...
@@ -26,5 +27,5 @@ import (
...
@@ -26,5 +27,5 @@ import (
func
newTestDockerService
()
(
*
dockerService
,
*
dockertools
.
FakeDockerClient
,
*
clock
.
FakeClock
)
{
func
newTestDockerService
()
(
*
dockerService
,
*
dockertools
.
FakeDockerClient
,
*
clock
.
FakeClock
)
{
fakeClock
:=
clock
.
NewFakeClock
(
time
.
Time
{})
fakeClock
:=
clock
.
NewFakeClock
(
time
.
Time
{})
c
:=
dockertools
.
NewFakeDockerClientWithClock
(
fakeClock
)
c
:=
dockertools
.
NewFakeDockerClientWithClock
(
fakeClock
)
return
&
dockerService
{
client
:
c
},
c
,
fakeClock
return
&
dockerService
{
client
:
c
,
os
:
&
containertest
.
FakeOS
{}
},
c
,
fakeClock
}
}
pkg/kubelet/kuberuntime/helpers.go
View file @
121a91eb
...
@@ -18,12 +18,14 @@ package kuberuntime
...
@@ -18,12 +18,14 @@ package kuberuntime
import
(
import
(
"fmt"
"fmt"
"path/filepath"
"strconv"
"strconv"
"github.com/golang/glog"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api"
runtimeApi
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
runtimeApi
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
kubecontainer
"k8s.io/kubernetes/pkg/kubelet/container"
kubecontainer
"k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/types"
)
)
const
(
const
(
...
@@ -199,3 +201,13 @@ func getStableKey(pod *api.Pod, container *api.Container) string {
...
@@ -199,3 +201,13 @@ func getStableKey(pod *api.Pod, container *api.Container) string {
hash
:=
strconv
.
FormatUint
(
kubecontainer
.
HashContainer
(
container
),
16
)
hash
:=
strconv
.
FormatUint
(
kubecontainer
.
HashContainer
(
container
),
16
)
return
fmt
.
Sprintf
(
"%s_%s_%s_%s_%s"
,
pod
.
Name
,
pod
.
Namespace
,
string
(
pod
.
UID
),
container
.
Name
,
hash
)
return
fmt
.
Sprintf
(
"%s_%s_%s_%s_%s"
,
pod
.
Name
,
pod
.
Namespace
,
string
(
pod
.
UID
),
container
.
Name
,
hash
)
}
}
// 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
)
}
// buildPodLogsDirectory builds absolute log directory path for a pod sandbox.
func
buildPodLogsDirectory
(
podUID
types
.
UID
)
string
{
return
filepath
.
Join
(
podLogsRootDirectory
,
string
(
podUID
))
}
pkg/kubelet/kuberuntime/kuberuntime_container.go
View file @
121a91eb
...
@@ -22,7 +22,7 @@ import (
...
@@ -22,7 +22,7 @@ import (
"io/ioutil"
"io/ioutil"
"math/rand"
"math/rand"
"os"
"os"
"path"
"path
/filepath
"
"sort"
"sort"
"sync"
"sync"
"time"
"time"
...
@@ -112,12 +112,9 @@ func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandb
...
@@ -112,12 +112,9 @@ func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandb
}
}
}
}
return
""
,
nil
// TODO(random-liu): Add legacy container log location support.
}
// getContainerLogsPath gets log path for container.
return
""
,
nil
func
getContainerLogsPath
(
containerName
string
,
podUID
kubetypes
.
UID
)
string
{
return
path
.
Join
(
podLogsRootDirectory
,
string
(
podUID
),
fmt
.
Sprintf
(
"%s.log"
,
containerName
))
}
}
// generateContainerConfig generates container config for kubelet runtime api.
// generateContainerConfig generates container config for kubelet runtime api.
...
@@ -128,7 +125,7 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *api.Conta
...
@@ -128,7 +125,7 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *api.Conta
}
}
command
,
args
:=
kubecontainer
.
ExpandContainerCommandAndArgs
(
container
,
opts
.
Envs
)
command
,
args
:=
kubecontainer
.
ExpandContainerCommandAndArgs
(
container
,
opts
.
Envs
)
containerLogsPath
:=
getContainerLogsPath
(
container
.
Name
,
pod
.
UID
)
containerLogsPath
:=
buildContainerLogsPath
(
container
.
Name
,
restartCount
)
podHasSELinuxLabel
:=
pod
.
Spec
.
SecurityContext
!=
nil
&&
pod
.
Spec
.
SecurityContext
.
SELinuxOptions
!=
nil
podHasSELinuxLabel
:=
pod
.
Spec
.
SecurityContext
!=
nil
&&
pod
.
Spec
.
SecurityContext
.
SELinuxOptions
!=
nil
restartCountUint32
:=
uint32
(
restartCount
)
restartCountUint32
:=
uint32
(
restartCount
)
config
:=
&
runtimeApi
.
ContainerConfig
{
config
:=
&
runtimeApi
.
ContainerConfig
{
...
@@ -269,7 +266,8 @@ func makeMounts(opts *kubecontainer.RunContainerOptions, container *api.Containe
...
@@ -269,7 +266,8 @@ func makeMounts(opts *kubecontainer.RunContainerOptions, container *api.Containe
// here we just add a random id to make the path unique for different instances
// here we just add a random id to make the path unique for different instances
// of the same container.
// of the same container.
cid
:=
makeUID
()
cid
:=
makeUID
()
containerLogPath
:=
path
.
Join
(
opts
.
PodContainerDir
,
cid
)
containerLogPath
:=
filepath
.
Join
(
opts
.
PodContainerDir
,
cid
)
// TODO: We should try to use os interface here.
fs
,
err
:=
os
.
Create
(
containerLogPath
)
fs
,
err
:=
os
.
Create
(
containerLogPath
)
if
err
!=
nil
{
if
err
!=
nil
{
glog
.
Errorf
(
"Error on creating termination-log file %q: %v"
,
containerLogPath
,
err
)
glog
.
Errorf
(
"Error on creating termination-log file %q: %v"
,
containerLogPath
,
err
)
...
@@ -690,7 +688,33 @@ func (m *kubeGenericRuntimeManager) ExecInContainer(containerID kubecontainer.Co
...
@@ -690,7 +688,33 @@ func (m *kubeGenericRuntimeManager) ExecInContainer(containerID kubecontainer.Co
return
fmt
.
Errorf
(
"not implemented"
)
return
fmt
.
Errorf
(
"not implemented"
)
}
}
// removeContainer removes the container and the container logs.
// Notice that we remove the container logs first, so that container will not be removed if
// container logs are failed to be removed, and kubelet will retry this later. This guarantees
// that container logs to be removed with the container.
// Notice that we assume that the container should only be removed in non-running state, and
// it will not write container logs anymore in that state.
func
(
m
*
kubeGenericRuntimeManager
)
removeContainer
(
containerID
string
)
error
{
glog
.
V
(
4
)
.
Infof
(
"Removing container %q"
,
containerID
)
// Cleanup the container log.
status
,
err
:=
m
.
runtimeService
.
ContainerStatus
(
containerID
)
if
err
!=
nil
{
glog
.
Errorf
(
"ContainerStatus for %q error: %v"
,
containerID
,
err
)
return
err
}
labeledInfo
:=
getContainerInfoFromLabels
(
status
.
Labels
)
annotatedInfo
:=
getContainerInfoFromAnnotations
(
status
.
Annotations
)
path
:=
filepath
.
Join
(
buildPodLogsDirectory
(
labeledInfo
.
PodUID
),
buildContainerLogsPath
(
labeledInfo
.
ContainerName
,
annotatedInfo
.
RestartCount
))
if
err
:=
m
.
osInterface
.
Remove
(
path
);
err
!=
nil
&&
!
os
.
IsNotExist
(
err
)
{
glog
.
Errorf
(
"Failed to remove container %q log %q: %v"
,
containerID
,
path
,
err
)
return
err
}
// Remove the container.
return
m
.
runtimeService
.
RemoveContainer
(
containerID
)
}
// DeleteContainer removes a container.
// DeleteContainer removes a container.
func
(
m
*
kubeGenericRuntimeManager
)
DeleteContainer
(
containerID
kubecontainer
.
ContainerID
)
error
{
func
(
m
*
kubeGenericRuntimeManager
)
DeleteContainer
(
containerID
kubecontainer
.
ContainerID
)
error
{
return
m
.
r
untimeService
.
R
emoveContainer
(
containerID
.
ID
)
return
m
.
removeContainer
(
containerID
.
ID
)
}
}
pkg/kubelet/kuberuntime/kuberuntime_container_test.go
0 → 100644
View file @
121a91eb
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
kuberuntime
import
(
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/kubernetes/pkg/api"
runtimeApi
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
containertest
"k8s.io/kubernetes/pkg/kubelet/container/testing"
)
// TestRemoveContainer tests removing the container and its corresponding container logs.
func
TestRemoveContainer
(
t
*
testing
.
T
)
{
fakeRuntime
,
_
,
m
,
err
:=
createTestRuntimeManager
()
pod
:=
&
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
UID
:
"12345678"
,
Name
:
"bar"
,
Namespace
:
"new"
,
},
Spec
:
api
.
PodSpec
{
Containers
:
[]
api
.
Container
{
{
Name
:
"foo"
,
Image
:
"busybox"
,
ImagePullPolicy
:
api
.
PullIfNotPresent
,
},
},
},
}
// Create fake sandbox and container
_
,
fakeContainers
,
err
:=
makeAndSetFakePod
(
m
,
fakeRuntime
,
pod
)
assert
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
len
(
fakeContainers
),
1
)
containerId
:=
fakeContainers
[
0
]
.
GetId
()
fakeOS
:=
m
.
osInterface
.
(
*
containertest
.
FakeOS
)
err
=
m
.
removeContainer
(
containerId
)
assert
.
NoError
(
t
,
err
)
// Verify container log is removed
expectedContainerLogPath
:=
filepath
.
Join
(
podLogsRootDirectory
,
"12345678"
,
"foo_0.log"
)
assert
.
Equal
(
t
,
fakeOS
.
Removes
,
[]
string
{
expectedContainerLogPath
})
// Verify container is removed
fakeRuntime
.
AssertCalls
([]
string
{
"RemoveContainer"
})
containers
,
err
:=
fakeRuntime
.
ListContainers
(
&
runtimeApi
.
ContainerFilter
{
Id
:
&
containerId
})
assert
.
NoError
(
t
,
err
)
assert
.
Empty
(
t
,
containers
)
}
pkg/kubelet/kuberuntime/kuberuntime_gc.go
View file @
121a91eb
...
@@ -17,6 +17,8 @@ limitations under the License.
...
@@ -17,6 +17,8 @@ limitations under the License.
package
kuberuntime
package
kuberuntime
import
(
import
(
"fmt"
"path/filepath"
"sort"
"sort"
"time"
"time"
...
@@ -116,26 +118,20 @@ func (cgc *containerGC) removeOldestN(containers []containerGCInfo, toRemove int
...
@@ -116,26 +118,20 @@ func (cgc *containerGC) removeOldestN(containers []containerGCInfo, toRemove int
// Remove from oldest to newest (last to first).
// Remove from oldest to newest (last to first).
numToKeep
:=
len
(
containers
)
-
toRemove
numToKeep
:=
len
(
containers
)
-
toRemove
for
i
:=
numToKeep
;
i
<
len
(
containers
);
i
++
{
for
i
:=
numToKeep
;
i
<
len
(
containers
);
i
++
{
cgc
.
removeContainer
(
containers
[
i
]
.
id
,
containers
[
i
]
.
name
)
if
err
:=
cgc
.
manager
.
removeContainer
(
containers
[
i
]
.
id
);
err
!=
nil
{
glog
.
Errorf
(
"Failed to remove container %q: %v"
,
containers
[
i
]
.
id
,
err
)
}
}
}
// Assume we removed the containers so that we're not too aggressive.
// Assume we removed the containers so that we're not too aggressive.
return
containers
[
:
numToKeep
]
return
containers
[
:
numToKeep
]
}
}
// removeContainer removes the container by containerID.
func
(
cgc
*
containerGC
)
removeContainer
(
containerID
,
containerName
string
)
{
glog
.
V
(
4
)
.
Infof
(
"Removing container %q name %q"
,
containerID
,
containerName
)
if
err
:=
cgc
.
client
.
RemoveContainer
(
containerID
);
err
!=
nil
{
glog
.
Warningf
(
"Failed to remove container %q: %v"
,
containerID
,
err
)
}
}
// removeSandbox removes the sandbox by sandboxID.
// removeSandbox removes the sandbox by sandboxID.
func
(
cgc
*
containerGC
)
removeSandbox
(
sandboxID
string
)
{
func
(
cgc
*
containerGC
)
removeSandbox
(
sandboxID
string
)
{
glog
.
V
(
4
)
.
Infof
(
"Removing sandbox %q"
,
sandboxID
)
glog
.
V
(
4
)
.
Infof
(
"Removing sandbox %q"
,
sandboxID
)
if
err
:=
cgc
.
client
.
RemovePodSandbox
(
sandboxID
);
err
!=
nil
{
if
err
:=
cgc
.
client
.
RemovePodSandbox
(
sandboxID
);
err
!=
nil
{
glog
.
Warning
f
(
"Failed to remove sandbox %q: %v"
,
sandboxID
,
err
)
glog
.
Error
f
(
"Failed to remove sandbox %q: %v"
,
sandboxID
,
err
)
}
}
}
}
...
@@ -184,7 +180,7 @@ func (cgc *containerGC) evictableContainers(minAge time.Duration) (containersByE
...
@@ -184,7 +180,7 @@ func (cgc *containerGC) evictableContainers(minAge time.Duration) (containersByE
// evictableSandboxes gets all sandboxes that are evictable. Evictable sandboxes are: not running
// evictableSandboxes gets all sandboxes that are evictable. Evictable sandboxes are: not running
// and contains no containers at all.
// and contains no containers at all.
func
(
cgc
*
containerGC
)
evictableSandboxes
()
([]
string
,
error
)
{
func
(
cgc
*
containerGC
)
evictableSandboxes
(
minAge
time
.
Duration
)
([]
string
,
error
)
{
containers
,
err
:=
cgc
.
manager
.
getKubeletContainers
(
true
)
containers
,
err
:=
cgc
.
manager
.
getKubeletContainers
(
true
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
@@ -196,7 +192,7 @@ func (cgc *containerGC) evictableSandboxes() ([]string, error) {
...
@@ -196,7 +192,7 @@ func (cgc *containerGC) evictableSandboxes() ([]string, error) {
}
}
evictSandboxes
:=
make
([]
string
,
0
)
evictSandboxes
:=
make
([]
string
,
0
)
newestGCTime
:=
time
.
Now
()
.
Add
(
-
sandboxMinGC
Age
)
newestGCTime
:=
time
.
Now
()
.
Add
(
-
min
Age
)
for
_
,
sandbox
:=
range
sandboxes
{
for
_
,
sandbox
:=
range
sandboxes
{
// Prune out ready sandboxes.
// Prune out ready sandboxes.
if
sandbox
.
GetState
()
==
runtimeApi
.
PodSandBoxState_READY
{
if
sandbox
.
GetState
()
==
runtimeApi
.
PodSandBoxState_READY
{
...
@@ -234,6 +230,30 @@ func (cgc *containerGC) isPodDeleted(podUID types.UID) bool {
...
@@ -234,6 +230,30 @@ func (cgc *containerGC) isPodDeleted(podUID types.UID) bool {
return
!
found
return
!
found
}
}
// evictPodLogsDirectories evicts all evictable pod logs directories. Pod logs directories
// are evictable if there are no corresponding pods.
func
(
cgc
*
containerGC
)
evictPodLogsDirectories
(
allSourcesReady
bool
)
error
{
osInterface
:=
cgc
.
manager
.
osInterface
if
allSourcesReady
{
// Only remove pod logs directories when all sources are ready.
dirs
,
err
:=
osInterface
.
ReadDir
(
podLogsRootDirectory
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to read podLogsRootDirectory %q: %v"
,
podLogsRootDirectory
,
err
)
}
for
_
,
dir
:=
range
dirs
{
podUID
:=
types
.
UID
(
dir
.
Name
())
if
!
cgc
.
isPodDeleted
(
podUID
)
{
continue
}
err
:=
osInterface
.
RemoveAll
(
filepath
.
Join
(
podLogsRootDirectory
,
dir
.
Name
()))
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to remove pod logs directory %q: %v"
,
dir
.
Name
(),
err
)
}
}
}
return
nil
}
// GarbageCollect removes dead containers using the specified container gc policy.
// GarbageCollect removes dead containers using the specified container gc policy.
// Note that gc policy is not applied to sandboxes. Sandboxes are only removed when they are
// Note that gc policy is not applied to sandboxes. Sandboxes are only removed when they are
// not ready and containing no containers.
// not ready and containing no containers.
...
@@ -289,7 +309,7 @@ func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy,
...
@@ -289,7 +309,7 @@ func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy,
}
}
// Remove sandboxes with zero containers
// Remove sandboxes with zero containers
evictSandboxes
,
err
:=
cgc
.
evictableSandboxes
()
evictSandboxes
,
err
:=
cgc
.
evictableSandboxes
(
sandboxMinGCAge
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -297,5 +317,7 @@ func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy,
...
@@ -297,5 +317,7 @@ func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy,
cgc
.
removeSandbox
(
sandbox
)
cgc
.
removeSandbox
(
sandbox
)
}
}
return
nil
// Remove pod sandbox log directory
// TODO(random-liu): Add legacy container log localtion cleanup.
return
cgc
.
evictPodLogsDirectories
(
allSourcesReady
)
}
}
pkg/kubelet/kuberuntime/kuberuntime_sandbox.go
View file @
121a91eb
...
@@ -38,6 +38,14 @@ func (m *kubeGenericRuntimeManager) createPodSandbox(pod *api.Pod, attempt uint3
...
@@ -38,6 +38,14 @@ func (m *kubeGenericRuntimeManager) createPodSandbox(pod *api.Pod, attempt uint3
return
""
,
message
,
err
return
""
,
message
,
err
}
}
// Create pod logs directory
err
=
m
.
osInterface
.
MkdirAll
(
podSandboxConfig
.
GetLogDirectory
(),
0755
)
if
err
!=
nil
{
message
:=
fmt
.
Sprintf
(
"Create pod log directory for pod %q failed: %v"
,
format
.
Pod
(
pod
),
err
)
glog
.
Errorf
(
message
)
return
""
,
message
,
err
}
podSandBoxID
,
err
:=
m
.
runtimeService
.
RunPodSandbox
(
podSandboxConfig
)
podSandBoxID
,
err
:=
m
.
runtimeService
.
RunPodSandbox
(
podSandboxConfig
)
if
err
!=
nil
{
if
err
!=
nil
{
message
:=
fmt
.
Sprintf
(
"CreatePodSandbox for pod %q failed: %v"
,
format
.
Pod
(
pod
),
err
)
message
:=
fmt
.
Sprintf
(
"CreatePodSandbox for pod %q failed: %v"
,
format
.
Pod
(
pod
),
err
)
...
@@ -82,6 +90,9 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *api.Pod, attem
...
@@ -82,6 +90,9 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *api.Pod, attem
podSandboxConfig
.
Hostname
=
&
hostname
podSandboxConfig
.
Hostname
=
&
hostname
}
}
logDir
:=
buildPodLogsDirectory
(
pod
.
UID
)
podSandboxConfig
.
LogDirectory
=
&
logDir
cgroupParent
:=
""
cgroupParent
:=
""
portMappings
:=
[]
*
runtimeApi
.
PortMapping
{}
portMappings
:=
[]
*
runtimeApi
.
PortMapping
{}
for
_
,
c
:=
range
pod
.
Spec
.
Containers
{
for
_
,
c
:=
range
pod
.
Spec
.
Containers
{
...
...
pkg/kubelet/kuberuntime/kuberuntime_sandbox_test.go
0 → 100644
View file @
121a91eb
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
kuberuntime
import
(
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/kubernetes/pkg/api"
runtimeApi
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
containertest
"k8s.io/kubernetes/pkg/kubelet/container/testing"
)
// TestCreatePodSandbox tests creating sandbox and its corresponding pod log directory.
func
TestCreatePodSandbox
(
t
*
testing
.
T
)
{
fakeRuntime
,
_
,
m
,
err
:=
createTestRuntimeManager
()
pod
:=
&
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
UID
:
"12345678"
,
Name
:
"bar"
,
Namespace
:
"new"
,
},
Spec
:
api
.
PodSpec
{
Containers
:
[]
api
.
Container
{
{
Name
:
"foo"
,
Image
:
"busybox"
,
ImagePullPolicy
:
api
.
PullIfNotPresent
,
},
},
},
}
fakeOS
:=
m
.
osInterface
.
(
*
containertest
.
FakeOS
)
fakeOS
.
MkdirAllFn
=
func
(
path
string
,
perm
os
.
FileMode
)
error
{
// Check pod logs root directory is created.
assert
.
Equal
(
t
,
filepath
.
Join
(
podLogsRootDirectory
,
"12345678"
),
path
)
assert
.
Equal
(
t
,
os
.
FileMode
(
0755
),
perm
)
return
nil
}
id
,
_
,
err
:=
m
.
createPodSandbox
(
pod
,
1
)
assert
.
NoError
(
t
,
err
)
fakeRuntime
.
AssertCalls
([]
string
{
"RunPodSandbox"
})
sandboxes
,
err
:=
fakeRuntime
.
ListPodSandbox
(
&
runtimeApi
.
PodSandboxFilter
{
Id
:
&
id
})
assert
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
len
(
sandboxes
),
1
)
// TODO Check pod sandbox configuration
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment