[JIRA] (JENKINS-61437) Kubernetes and vault-credential plugins results in too many open files

11 views
Skip to first unread message

lho@trifork.com (JIRA)

unread,
Mar 11, 2020, 11:05:04 AM3/11/20
to jenkinsc...@googlegroups.com
Lasse Højgaard created an issue
 
Jenkins / Bug JENKINS-61437
Kubernetes and vault-credential plugins results in too many open files
Issue Type: Bug Bug
Assignee: Peter Tierno
Components: hashicorp-vault-plugin, kubernetes-plugin
Created: 2020-03-11 15:04
Environment: Jenkins 2.204.5
Installed via helm chart version "1.9.21"
Installed plugins:
    - blueocean:1.22.0
    - command-launcher:1.4
    - config-file-provider:3.6.3
    - configuration-as-code:1.36
    - credentials-binding:1.21
    - file-leak-detector:1.6
    - git:4.2.0
    - hashicorp-vault-plugin:3.2.0
    - jdk-tool:1.4
    - job-dsl:1.76
    - kubernetes:1.24.1
    - matrix-auth:2.5
    - oic-auth:1.7
    - pipeline-aws:1.39
    - pipeline-github-lib:1.0
    - pipeline-utility-steps:2.5.0
    - workflow-aggregator:2.6

Running on AWS EKS. Kubernetes version: v1.14.8
Priority: Minor Minor
Reporter: Lasse Højgaard

Hi,

Provisioning build agents on kubernetes somehow results in "Too Many Open Files".

``` $ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
jenkins 1 0.0 0.0 1148 4 ? Ss Mar06 0:11 /sbin/tini – /usr/local/bin/jenkins.sh --argumentsRealm.passwd.admin=${MASTER_ADMIN_PASSWORD} --argumentsRealm.roles.admin=admin --httpPort=8080
jenkins 7 1.1 7.1 3841028 1167032 ? Sl Mar06 82:21 java -Duser.home=/var/jenkins_home -Dpermissive-script-security.enabled=true -Xms512m -Xmx1024m -XX:MaxMetaspaceSize=200m -XX:CompressedClassSpaceSize=100m -Djenkins.model.Jenkins.slaveAgentPort=50000 -jar /
jenkins 15138 0.0 0.0 19976 3656 pts/0 Ss+ 14:46 0:00 bash
jenkins 15922 0.1 0.0 19972 3436 pts/1 Ss 14:57 0:00 bash
jenkins 15927 0.0 0.0 38384 3264 pts/1 R+ 14:58 0:00 ps aux

$ ls -la /proc/7/fd | head -n 20
total 0
dr-x------. 2 jenkins jenkins 0 Mar 11 14:46 .
dr-xr-xr-x. 9 jenkins jenkins 0 Mar 11 14:46 ..
lrwx------. 1 jenkins jenkins 64 Mar 11 14:46 0 -> /dev/null
l-wx------. 1 jenkins jenkins 64 Mar 11 14:46 1 -> pipe:[295935440]
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10 -> /dev/urandom
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 100 -> /var/jenkins_home/war/WEB-INF/lib/localizer-1.26.jar
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 1000 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10000 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10001 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10002 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10003 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10004 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10005 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10006 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10007 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10008 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10009 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 1001 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token
lr-x------. 1 jenkins jenkins 64 Mar 11 14:46 10010 -> /run/secrets/kubernetes.io/serviceaccount/..2020_03_06_12_39_51.580529302/token

$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
66108

```

If I start a a build there's a few leaked file descriptors:

```

jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64725 # before build
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64735
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64741
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64741
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64741 # after build ends

```

An example of the kinds of jobs we're using
```
#!/usr/bin/groovy

// load pipeline functions
// Requires pipeline-github-lib plugin to load library from github

@Library('github.com/lachie83/jenkins-pipeline@dev')
@Library('github.com/comquent/imperative-when@9ee7fbb323f2b106c4404473cfca50a3948fe1a6')

_ = library identifier: 'plugin@master', retriever: modernSCM(
[$class: 'GitSCMSource',
remote: 'g...@gitserver.mydomain.com/jenkins-plugin',
credentialsId: 'creds'])

def pipeline = new io.estrado.Pipeline()
def label = "${env.BUILD_TAG{color:#569cd6}}".toLowerCase().replaceAll(/[^-\w]/, '-')

podTemplate(label: label,
containers: [
containerTemplate(name: 'helm', image: 'image', command: 'cat', ttyEnabled: true),
],
imagePullSecrets: [
'harbor'
],
volumes:[
hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),
persistentVolumeClaim(claimName: 'jenkins-maven-repo', mountPath: '/root/.m2/repository/')
]){

node (label) {

checkout scm

// read in required jenkins workflow config values
def inputFile = readFile('Jenkinsfile.json')
def config = new groovy.json.JsonSlurperClassic().parseText(inputFile)
println "pipeline config ==> ${config{color:#569cd6}}"

// continue only if pipeline enabled
if (!config.pipeline.enabled) {
println "pipeline disabled"
return
}

// set additional git envvars for image tagging
pipeline.gitEnvVars()

// If pipeline debugging enabled
if (config.pipeline.debug) {
println "DEBUG ENABLED"
println "pipeline config ==> ${config{color:#569cd6}}"
sh "env | sort"
}

chartFiles = findFiles(glob: 'charts/*/Chart.yaml')

stage ('lint helm charts') {
chartFiles.each { chartFile ->
directory = chartFile.path.minus('/Chart.yaml')
container('helm') {
pipeline.helmLint(directory)
}
}
}

stage ('publish helm charts') {
when (BRANCH_NAME == 'master') {
chartFiles.each { chartFile ->
directory = chartFile.path.minus('/Chart.yaml')
chartName = directory.split('/').last()
specificConfig = config
specificConfig.chart_repo.repo = chartName
specificConfig.chart_repo.directory = directory + '/'
container('helm') {
String chart_version = helm.getChartVersion(config, env.BRANCH_NAME)
helm.packageChart(config, chart_version)
helm.uploadToHarborChartMuseum(config, chart_version)
}
}
}
}
}
{color:#d4d4d4}}
```

I know that this might now be enough to debug the problem fully - so please let me know if more info is required.

Add Comment Add Comment
 
This message was sent by Atlassian Jira (v7.13.12#713012-sha1:6e07c38)
Atlassian logo

lho@trifork.com (JIRA)

unread,
Mar 11, 2020, 11:26:05 AM3/11/20
to jenkinsc...@googlegroups.com
Lasse Højgaard commented on Bug JENKINS-61437
 
Re: Kubernetes and vault-credential plugins results in too many open files

I've done more digging:

Even running a scan on a multibranch pipeline leaks file descriptors:

 

$ # before
$ ls -la /proc/6/fd  | cut -d ' ' -f11 | grep -i token | wc -l
233

$ # after
$ ls -la /proc/6/fd  | cut -d ' ' -f11 | grep -i token | wc -l
458

I've installed the plugin file-leak-detector v 1.6 but it reporting 0 open file descriptors:

0 descriptors are open
----

So now I'm not so sure that it's related to the hashicorp-vault-plugin but more to the kubernetes plugin.

 

 

lho@trifork.com (JIRA)

unread,
Mar 11, 2020, 11:29:06 AM3/11/20
to jenkinsc...@googlegroups.com
Lasse Højgaard updated an issue
 
Change By: Lasse Højgaard
Hi,

Provisioning build agents on kubernetes somehow results in "Too Many Open Files".
{code:java}
``` $ ps aux

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
jenkins 1 0.0 0.0 1148 4 ? Ss Mar06 0:11 /sbin/tini -- /usr/local/bin/jenkins.sh --argumentsRealm.passwd.admin=${MASTER_ADMIN_PASSWORD} --argumentsRealm.roles.admin=admin --httpPort=8080
$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
66108
{code}
```

If I start a a build there's a few leaked file descriptors:

```  
{code:java}
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64725 # before build
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64735
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64741
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64741
jenkins@jenkins-579698569c-nh4g8:/$ ls -la /proc/6/fd | cut -d ' ' -f11 | grep -i token | wc -l
64741 # after build ends {code}
 
```
 

An example of the kinds of jobs we're using
```
{ color code : #6a9955 java }
#!/usr/bin/groovy {color}

{color:#6a9955}
// load pipeline functions {color}
{color:#6a9955} // Requires pipeline-github-lib plugin to load library from github {color}

{color:#4ec9b0}
@Library {color}{color:#d4d4d4} ( {color}{color:#ce9178} 'github.com/lachie83/jenkins-pipeline@dev' {color}{color:#d4d4d4} ) {color}
{color:#4ec9b0} @Library {color}{color:#d4d4d4} ( {color}{color:#ce9178} 'github.com/comquent/imperative-when@9ee7fbb323f2b106c4404473cfca50a3948fe1a6' {color}{color:#d4d4d4} ) {color}

{color:#d4d4d4}
_ = library identifier: {color}{color:#ce9178} 'plugin@master' {color}{color:#d4d4d4} , retriever: modernSCM( {color}
{color:#d4d4d4} [$class: {color}{color:#ce9178} 'GitSCMSource' {color}{color:#d4d4d4} , {color}
{color:#d4d4d4} remote: {color}{color:#ce9178} 'g...@gitserver.mydomain.com/jenkins-plugin' {color}{color:#d4d4d4} , {color}
{color:#d4d4d4} credentialsId: {color}{color:#ce9178} 'creds' {color}{color:#d4d4d4} ]) {color}

{color:#569cd6}
def {color} {color:#9cdcfe} pipeline {color}{color:#d4d4d4} = {color}{color:#c586c0} new {color} {color:#4ec9b0} io.estrado.Pipeline {color}{color:#d4d4d4} () {color}
{color:#569cd6} def {color} {color:#9cdcfe} label {color}{color:#d4d4d4} = {color}{color:#ce9178} " {color}{color:#569cd6} ${ {color}{color:#d4d4d4} env.BUILD_TAG{color }{color :#569cd6}} {color}{color:#ce9178} " {color}{color:#d4d4d4} .toLowerCase().replaceAll( {color}{color:#d16969} /[^- {color}{color:#d7ba7d} \w {color}{color:#d16969} ]/ {color}{color:#d4d4d4} , {color}{color:#ce9178} '-' {color}{color:#d4d4d4} ) {color}

{color:#d4d4d4}
podTemplate(label: label, {color}
{color:#d4d4d4} containers: [ {color}
{color:#d4d4d4} containerTemplate(name: {color}{color:#ce9178} 'helm' {color}{color:#d4d4d4} , image: 'image {color}{color:#ce9178} ' {color}{color:#d4d4d4} , command: {color}{color:#ce9178} 'cat' {color}{color:#d4d4d4} , ttyEnabled: {color}{color:#569cd6} true {color}{color:#d4d4d4} ), {color}
{color:#d4d4d4} ], {color}
{color:#d4d4d4} imagePullSecrets: [ {color}
{color:#ce9178} 'harbor' {color}
{color:#d4d4d4} ], {color}
{color:#d4d4d4} volumes:[ {color}
{color:#d4d4d4} hostPathVolume(mountPath: {color}{color:#ce9178} '/var/run/docker.sock' {color}{color:#d4d4d4} , hostPath: {color}{color:#ce9178} '/var/run/docker.sock' {color}{color:#d4d4d4} ), {color}
{color:#d4d4d4} persistentVolumeClaim(claimName: {color}{color:#ce9178} 'jenkins-maven-repo' {color}{color:#d4d4d4} , mountPath: {color}{color:#ce9178} '/root/.m2/repository/' {color}{color:#d4d4d4} ) {color}
{color:#d4d4d4} ]){ {color}

{color:#d4d4d4}
node (label) { {color}

{color:#d4d4d4}
checkout scm {color}

{color:#6a9955}
// read in required jenkins workflow config values {color}
{color:#569cd6} def {color}{color:#d4d4d4} inputFile = readFile( {color}{color:#ce9178} 'Jenkinsfile.json' {color}{color:#d4d4d4} ) {color}
{color:#569cd6} def {color}{color:#d4d4d4} config = {color}{color:#c586c0} new {color} {color:#4ec9b0} groovy.json.JsonSlurperClassic {color}{color:#d4d4d4} ().parseText(inputFile) {color}
{color:#dcdcaa} println {color} {color:#ce9178} "pipeline config ==> {color}{color:#569cd6} ${ {color}{color:#d4d4d4} config{color }{color :#569cd6}} {color}{color:#ce9178} " {color}

{color:#6a9955}
// continue only if pipeline enabled {color}
{color:#c586c0} if {color}{color:#d4d4d4} (!config.pipeline.enabled) { {color}
{color:#dcdcaa} println {color} {color:#ce9178} "pipeline disabled" {color}
{color:#c586c0} return {color}
{color:#d4d4d4 } }{color}

{color:#6a9955}
// set additional git envvars for image tagging {color}
{color:#d4d4d4} pipeline.gitEnvVars() {color}


{color:#6a9955}
// If pipeline debugging enabled {color}
{color:#c586c0} if {color}{color:#d4d4d4} (config.pipeline.debug) { {color}
{color:#dcdcaa} println {color} {color:#ce9178} "DEBUG ENABLED" {color}
{color:#dcdcaa} println {color} {color:#ce9178} "pipeline config ==> {color}{color:#569cd6} ${ {color}{color:#d4d4d4} config{color }{color :#569cd6}} {color}{color:#ce9178} " {color}
{color:#d4d4d4} sh {color}{color:#ce9178} "env | sort" {color}
{color:#d4d4d4 } }{color}

{color:#d4d4d4}
chartFiles = findFiles(glob: {color}{color:#ce9178} 'charts/*/Chart.yaml' {color}{color:#d4d4d4} ) {color}

{color:#d4d4d4}
stage ( {color}{color:#ce9178} 'lint helm charts' {color}{color:#d4d4d4} ) { {color}
{color:#d4d4d4} chartFiles.each { {color}{color:#9cdcfe} chartFile {color}{color:#d4d4d4} -> {color}
{color:#d4d4d4}

directory = chartFile.path.minus( {color}{color:#ce9178} '/Chart.yaml' {color}{color:#d4d4d4} ) {color}
{color:#d4d4d4} container( {color}{color:#ce9178} 'helm' {color}{color:#d4d4d4} ) { {color}
{color:#d4d4d4} pipeline.helmLint(directory) {color}
{color:#d4d4d4 } }{color}
{color:#d4d4d4 } }{color}
{color:#d4d4d4 } }{color}

{color:#d4d4d4}
stage ( {color}{color:#ce9178} 'publish helm charts' {color}{color:#d4d4d4} ) { {color}
{color:#d4d4d4} when (BRANCH_NAME == {color}{color:#ce9178} 'master' {color}{color:#d4d4d4} ) { {color}
{color:#d4d4d4} chartFiles.each { {color}{color:#9cdcfe} chartFile {color}{color:#d4d4d4} -> {color}
{color:#d4d4d4}

directory = chartFile.path.minus( {color}{color:#ce9178} '/Chart.yaml' {color}{color:#d4d4d4} ) {color}
{color:#d4d4d4} chartName = directory.split( {color}{color:#ce9178} '/' {color}{color:#d4d4d4} ).last() {color}
{color:#d4d4d4} specificConfig = config {color}
{color:#d4d4d4} specificConfig.chart_repo.repo = chartName {color}
{color:#d4d4d4} specificConfig.chart_repo.directory = directory + {color}{color:#ce9178} '/' {color}
{color:#d4d4d4} container( {color}{color:#ce9178} 'helm' {color}{color:#d4d4d4} ) { {color}
{color:#4ec9b0} String {color}{color:#d4d4d4} chart_version = helm.getChartVersion(config, env.BRANCH_NAME) {color}
{color:#d4d4d4} helm.packageChart(config, chart_version) {color}
{color:#d4d4d4} helm.uploadToHarborChartMuseum(config, chart_version) {color}
{color:#d4d4d4 } }{color}
{color:#d4d4d4 } }{color}
{color:#d4d4d4 }
} {color}
{color:#d4d4d4 } }{color}
{
color:#d4d4d4 code } }{color}
{color:#d4d4d4}}{color}
```

I know that this might now be enough to debug the problem fully - so please let me know if more what kind of info is required.

frede@server-1.dk (JIRA)

unread,
Apr 14, 2020, 6:26:02 AM4/14/20
to jenkinsc...@googlegroups.com

lho@trifork.com (JIRA)

unread,
Apr 14, 2020, 6:45:03 AM4/14/20
to jenkinsc...@googlegroups.com
Lasse Højgaard updated Bug JENKINS-61437
 

As Frederik Mogensen mentioned this has been fixed by a new release of hashicorp-vault-plugin which uses try-with-resources to access the kubernetes service account JWT.

Released as 3.3.0: https://github.com/jenkinsci/hashicorp-vault-plugin/releases/tag/hashicorp-vault-plugin-3.3.0

Change By: Lasse Højgaard
Status: Open Fixed but Unreleased
Resolution: Fixed
Released As: hashicorp-vault-plugin v3.3.0

lho@trifork.com (JIRA)

unread,
Apr 14, 2020, 6:46:02 AM4/14/20
to jenkinsc...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages