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
2fbf34f7
Commit
2fbf34f7
authored
Apr 12, 2017
by
Random-Liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Stop following container log when container exited.
parent
a4354569
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
50 additions
and
29 deletions
+50
-29
kuberuntime_container.go
pkg/kubelet/kuberuntime/kuberuntime_container.go
+4
-4
kuberuntime_logs.go
pkg/kubelet/kuberuntime/kuberuntime_logs.go
+46
-25
No files found.
pkg/kubelet/kuberuntime/kuberuntime_container.go
View file @
2fbf34f7
...
@@ -357,10 +357,10 @@ func getTerminationMessage(status *runtimeapi.ContainerStatus, terminationMessag
...
@@ -357,10 +357,10 @@ func getTerminationMessage(status *runtimeapi.ContainerStatus, terminationMessag
// readLastStringFromContainerLogs attempts to read up to the max log length from the end of the CRI log represented
// readLastStringFromContainerLogs attempts to read up to the max log length from the end of the CRI log represented
// by path. It reads up to max log lines.
// by path. It reads up to max log lines.
func
readLastStringFromContainerLogs
(
path
string
)
string
{
func
(
m
*
kubeGenericRuntimeManager
)
readLastStringFromContainerLogs
(
path
string
)
string
{
value
:=
int64
(
kubecontainer
.
MaxContainerTerminationMessageLogLines
)
value
:=
int64
(
kubecontainer
.
MaxContainerTerminationMessageLogLines
)
buf
,
_
:=
circbuf
.
NewBuffer
(
kubecontainer
.
MaxContainerTerminationMessageLogLength
)
buf
,
_
:=
circbuf
.
NewBuffer
(
kubecontainer
.
MaxContainerTerminationMessageLogLength
)
if
err
:=
ReadLogs
(
path
,
&
v1
.
PodLogOptions
{
TailLines
:
&
value
},
buf
,
buf
);
err
!=
nil
{
if
err
:=
m
.
ReadLogs
(
path
,
""
,
&
v1
.
PodLogOptions
{
TailLines
:
&
value
},
buf
,
buf
);
err
!=
nil
{
return
fmt
.
Sprintf
(
"Error on reading termination message from logs: %v"
,
err
)
return
fmt
.
Sprintf
(
"Error on reading termination message from logs: %v"
,
err
)
}
}
return
buf
.
String
()
return
buf
.
String
()
...
@@ -414,7 +414,7 @@ func (m *kubeGenericRuntimeManager) getPodContainerStatuses(uid kubetypes.UID, n
...
@@ -414,7 +414,7 @@ func (m *kubeGenericRuntimeManager) getPodContainerStatuses(uid kubetypes.UID, n
tMessage
,
checkLogs
:=
getTerminationMessage
(
status
,
annotatedInfo
.
TerminationMessagePath
,
fallbackToLogs
)
tMessage
,
checkLogs
:=
getTerminationMessage
(
status
,
annotatedInfo
.
TerminationMessagePath
,
fallbackToLogs
)
if
checkLogs
{
if
checkLogs
{
path
:=
buildFullContainerLogsPath
(
uid
,
labeledInfo
.
ContainerName
,
annotatedInfo
.
RestartCount
)
path
:=
buildFullContainerLogsPath
(
uid
,
labeledInfo
.
ContainerName
,
annotatedInfo
.
RestartCount
)
tMessage
=
readLastStringFromContainerLogs
(
path
)
tMessage
=
m
.
readLastStringFromContainerLogs
(
path
)
}
}
// Use the termination message written by the application is not empty
// Use the termination message written by the application is not empty
if
len
(
tMessage
)
!=
0
{
if
len
(
tMessage
)
!=
0
{
...
@@ -688,7 +688,7 @@ func (m *kubeGenericRuntimeManager) GetContainerLogs(pod *v1.Pod, containerID ku
...
@@ -688,7 +688,7 @@ func (m *kubeGenericRuntimeManager) GetContainerLogs(pod *v1.Pod, containerID ku
labeledInfo
:=
getContainerInfoFromLabels
(
status
.
Labels
)
labeledInfo
:=
getContainerInfoFromLabels
(
status
.
Labels
)
annotatedInfo
:=
getContainerInfoFromAnnotations
(
status
.
Annotations
)
annotatedInfo
:=
getContainerInfoFromAnnotations
(
status
.
Annotations
)
path
:=
buildFullContainerLogsPath
(
pod
.
UID
,
labeledInfo
.
ContainerName
,
annotatedInfo
.
RestartCount
)
path
:=
buildFullContainerLogsPath
(
pod
.
UID
,
labeledInfo
.
ContainerName
,
annotatedInfo
.
RestartCount
)
return
ReadLogs
(
path
,
logOptions
,
stdout
,
stderr
)
return
m
.
ReadLogs
(
path
,
containerID
.
ID
,
logOptions
,
stdout
,
stderr
)
}
}
// GetExec gets the endpoint the runtime will serve the exec request from.
// GetExec gets the endpoint the runtime will serve the exec request from.
...
...
pkg/kubelet/kuberuntime/kuberuntime_logs.go
View file @
2fbf34f7
...
@@ -32,6 +32,7 @@ import (
...
@@ -32,6 +32,7 @@ import (
"github.com/golang/glog"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/v1"
runtimeapi
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
"k8s.io/kubernetes/pkg/util/tail"
"k8s.io/kubernetes/pkg/util/tail"
)
)
...
@@ -54,6 +55,11 @@ const (
...
@@ -54,6 +55,11 @@ const (
timeFormat
=
time
.
RFC3339Nano
timeFormat
=
time
.
RFC3339Nano
// blockSize is the block size used in tail.
// blockSize is the block size used in tail.
blockSize
=
1024
blockSize
=
1024
// stateCheckPeriod is the period to check container state while following
// the container log. Kubelet should not keep following the log when the
// container is not running.
stateCheckPeriod
=
5
*
time
.
Second
)
)
var
(
var
(
...
@@ -110,7 +116,9 @@ func newLogOptions(apiOpts *v1.PodLogOptions, now time.Time) *logOptions {
...
@@ -110,7 +116,9 @@ func newLogOptions(apiOpts *v1.PodLogOptions, now time.Time) *logOptions {
}
}
// ReadLogs read the container log and redirect into stdout and stderr.
// ReadLogs read the container log and redirect into stdout and stderr.
func
ReadLogs
(
path
string
,
apiOpts
*
v1
.
PodLogOptions
,
stdout
,
stderr
io
.
Writer
)
error
{
// Note that containerID is only needed when following the log, or else
// just pass in empty string "".
func
(
m
*
kubeGenericRuntimeManager
)
ReadLogs
(
path
,
containerID
string
,
apiOpts
*
v1
.
PodLogOptions
,
stdout
,
stderr
io
.
Writer
)
error
{
f
,
err
:=
os
.
Open
(
path
)
f
,
err
:=
os
.
Open
(
path
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to open log file %q: %v"
,
path
,
err
)
return
fmt
.
Errorf
(
"failed to open log file %q: %v"
,
path
,
err
)
...
@@ -166,8 +174,8 @@ func ReadLogs(path string, apiOpts *v1.PodLogOptions, stdout, stderr io.Writer)
...
@@ -166,8 +174,8 @@ func ReadLogs(path string, apiOpts *v1.PodLogOptions, stdout, stderr io.Writer)
}
}
}
}
// Wait until the next log change.
// Wait until the next log change.
if
err
:=
waitLogs
(
watcher
);
err
!=
nil
{
if
found
,
err
:=
m
.
waitLogs
(
containerID
,
watcher
);
!
found
{
return
fmt
.
Errorf
(
"failed to wait logs for log file %q: %v"
,
path
,
err
)
return
err
}
}
continue
continue
}
}
...
@@ -196,6 +204,41 @@ func ReadLogs(path string, apiOpts *v1.PodLogOptions, stdout, stderr io.Writer)
...
@@ -196,6 +204,41 @@ func ReadLogs(path string, apiOpts *v1.PodLogOptions, stdout, stderr io.Writer)
}
}
}
}
// waitLogs wait for the next log write. It returns a boolean and an error. The boolean
// indicates whether a new log is found; the error is error happens during waiting new logs.
func
(
m
*
kubeGenericRuntimeManager
)
waitLogs
(
id
string
,
w
*
fsnotify
.
Watcher
)
(
bool
,
error
)
{
errRetry
:=
5
for
{
select
{
case
e
:=
<-
w
.
Events
:
switch
e
.
Op
{
case
fsnotify
.
Write
:
return
true
,
nil
default
:
glog
.
Errorf
(
"Unexpected fsnotify event: %v, retrying..."
,
e
)
}
case
err
:=
<-
w
.
Errors
:
glog
.
Errorf
(
"Fsnotify watch error: %v, %d error retries remaining"
,
err
,
errRetry
)
if
errRetry
==
0
{
return
false
,
err
}
errRetry
--
case
<-
time
.
After
(
stateCheckPeriod
)
:
s
,
err
:=
m
.
runtimeService
.
ContainerStatus
(
id
)
if
err
!=
nil
{
return
false
,
err
}
// Only keep following container log when it is running.
if
s
.
State
!=
runtimeapi
.
ContainerState_CONTAINER_RUNNING
{
glog
.
Errorf
(
"Container %q is not running (state=%q)"
,
id
,
s
.
State
)
// Do not return error because it's normal that the container stops
// during waiting.
return
false
,
nil
}
}
}
}
// parseFunc is a function parsing one log line to the internal log type.
// parseFunc is a function parsing one log line to the internal log type.
// Notice that the caller must make sure logMessage is not nil.
// Notice that the caller must make sure logMessage is not nil.
type
parseFunc
func
([]
byte
,
*
logMessage
)
error
type
parseFunc
func
([]
byte
,
*
logMessage
)
error
...
@@ -267,28 +310,6 @@ func getParseFunc(log []byte) (parseFunc, error) {
...
@@ -267,28 +310,6 @@ func getParseFunc(log []byte) (parseFunc, error) {
return
nil
,
fmt
.
Errorf
(
"unsupported log format: %q"
,
log
)
return
nil
,
fmt
.
Errorf
(
"unsupported log format: %q"
,
log
)
}
}
// waitLogs wait for the next log write.
func
waitLogs
(
w
*
fsnotify
.
Watcher
)
error
{
errRetry
:=
5
for
{
select
{
case
e
:=
<-
w
.
Events
:
switch
e
.
Op
{
case
fsnotify
.
Write
:
return
nil
default
:
glog
.
Errorf
(
"Unexpected fsnotify event: %v, retrying..."
,
e
)
}
case
err
:=
<-
w
.
Errors
:
glog
.
Errorf
(
"Fsnotify watch error: %v, %d error retries remaining"
,
err
,
errRetry
)
if
errRetry
==
0
{
return
err
}
errRetry
--
}
}
}
// logWriter controls the writing into the stream based on the log options.
// logWriter controls the writing into the stream based on the log options.
type
logWriter
struct
{
type
logWriter
struct
{
stdout
io
.
Writer
stdout
io
.
Writer
...
...
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