Jenkins build Docker daemon not running on kubernetes cluster - docker

I'm new to Dev Ops and trying to build my code using Jenkins and upload it on the kubernetes cluster which is hosted on the IBM cloud. But when I run the Docker run command in the Jenkins script I keep getting this error. Installed all the latest plugins and
+ docker run hello-world
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
Here's the Jenkins script which I don't know is right or wrong. I searched a couple of articles and question. They all were not giving me a positive result.
Tried this Jenkins Docker in Docker on GCP/Kubernetes.
podTemplate(
cloud: "kubernetes",
label:"mypod",
containers:[
containerTemplate(
name:"nodejs",
image:"node",
ttyEnabled:true,
command:'cat',
alwaysPullImage: true,
resourceRequestCpu: '200m',
resourceRequestMemory: '100Mi',
),
containerTemplate(
name:"docker",
image:"",
ttyEnabled:true,
command:'cat',
alwaysPullImage: true,
resourceRequestCpu: '200m',
resourceRequestMemory: '100Mi',
),
containerTemplate(
name:"helm",
image:"alpine/helm",
ttyEnabled:true,
command:'cat',
alwaysPullImage: true,
resourceRequestCpu: '200m',
resourceRequestMemory: '100Mi',
)
],
volumes:[
hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock')
]
){
node("mypod"){
def commitId
stage ("Fetch repo"){
checkout scm
commitId = sh(script: 'git rev-parse --short HEAD',returnStdout:true).trim()
}
stage ("Installing packages"){
container("nodejs"){
sh 'npm install'
}
}
stage ("Build"){
container("nodejs"){
sh 'npm run build'
}
}
def repository
stage ("Docker"){
container('docker'){
docker.withRegistry("https://us.icr.io/api","ibm-cloud"){
sh "docker run hello-world"
}
}
}
stage ("Deploy"){
container ("helm"){
sh 'helm version'
}
}
}
}
This is the deployment file of my Jenkins pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins-uat
labels:
app: jenkins
chart: jenkins-5.0.18
release: jenkins-uat
heritage: Helm
spec:
selector:
matchLabels:
app: jenkins
release: jenkins-uat
template:
metadata:
labels:
app: jenkins
chart: jenkins-5.0.18
release: jenkins-uat
heritage: Helm
spec:
securityContext:
fsGroup: 1001
containers:
- name: jenkins
image: docker.io/bitnami/jenkins:2.235.1-debian-10-r7
imagePullPolicy: "IfNotPresent"
securityContext:
runAsUser: 1001
env:
- name: JENKINS_USERNAME
value: "hlpjenkin"
- name: JENKINS_PASSWORD
valueFrom:
secretKeyRef:
name: jenkins-uat
key: jenkins-password
- name: JENKINS_HOME
value: "/opt/bitnami/jenkins/jenkins_home"
- name: DISABLE_JENKINS_INITIALIZATION
value: "no"
ports:
- name: http
containerPort: 8080
- name: https
containerPort: 8443
livenessProbe:
httpGet:
path: /login
port: http
initialDelaySeconds: 180
periodSeconds: 10
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 6
readinessProbe:
httpGet:
path: /login
port: http
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
resources:
limits: {}
requests:
cpu: 300m
memory: 512Mi
volumeMounts:
- name: jenkins-data
mountPath: /bitnami/jenkins
volumes:
- name: jenkins-data
persistentVolumeClaim:
claimName: jenkins-uat

So I have installed Jenkins as a container in my k8s cluster :) and managed to reproduce the same error:
docker run --rm hello-world
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.
How to fix it.
In order to fix you definitely need to have access to the Docker on your K8s Node. Very good explanation of how that works was given by jpetazzo.
Technically you do not need "Docker in Docker" (that is the "full Docker setup" in Docker). You just want to be able to run Docker from your CI system, while this CI system itself is in a container. So that that your CI system like Jenkins can start containers.
So when you start your CI container (Jenkins or other), instead of hacking something together with Docker-in-Docker, start it with the access to /var/run/docker.sock on main host.
Below you can see the part of my Yamls that a responsible for that.
That allows my CI container to have access to the Docker socket, and CI container will, therefore, be able to start containers.
Except that instead of starting “child” containers, it will start “sibling” containers, but that is perfectly fine in our context.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
...
spec:
template:
spec:
containers:
- env:
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-sock
...
volumes:
- hostPath:
path: /var/run/docker.sock
type: File
name: docker-sock
So in my case, the pipeline I've created produces the following logs:
####pipeline
pipeline {
agent any
stages {
stage('second_stage'){
steps{
sh 'docker run --rm hello-world'
}
}
}
}
####logs
+ docker run --rm hello-world
Hello from Docker!

I had this similar problem and I fixed this by enabling my user to be part of docker group and execute docker. This happens when your user is unable to find docker.
You need follow the post installation steps after installing docker.
Create the docker group
sudo groupadd docker
Add your user to the docker group.
sudo usermod -aG docker $USER
Restart docker service
sudo service docker stop and sudo service docker start
Exit/Logout from current user and Log back in to verify

So I see a couple of problems in your podtemplate.
First of all, for docker container, you didn't specify any image. You should use a docker image in this container. Create your own container with docker installed in it or you can use https://hub.docker.com/r/volaka/ibm-cloud-cli this image. It includes ibmcloud cli, kubectl, helm and docker for kubernetes automation on IBM Cloud.
Second thing is that I think it is related with Jenkins Kubernetes. Once you create a podTemplate in a pipeline, even if you edit the template, sometimes the changes are not seen in the latest pod. I had this kind of error so I deleted and recreated the pipeline with the edited podTemplate. I am saying this because even if you have declared your volume binding in podTemplate, I don't see it in the created pod's yaml. So I recommend you to recreate your pipeline with your final podTemplate.
I have created a detailed walkthrough about how to install, configure and automate Jenkins pipelines on IBM Kubernetes Service. Feel free to check it. https://volaka.gitbook.io/jenkins-on-k8s/

Related

Deploying in 1.24 version Kubernetes

As you already know , Kubernetes in version 1.24 is moving on from DockerShim.
I will need your help here because all of our deployments in Jenkins are running through a Docker Pod agent via Kubernetes plugin from Jenkins.
I will give you an example of part from our pipelines in Jenkins:
agent {
kubernetes {
// label 'test'
defaultContainer 'jnlp'
yaml """
apiVersion: v1
kind: Pod
metadata:
labels:
component: ci
spec:
# Use service account that can deploy to all namespaces
serviceAccountName: jenkins
containers:
- name: docker
image: docker:latest
#image: debian:buster
command:
- cat
tty: true
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-sock
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
"""
And then basically in this stage we build our image :
stage('Create & Tag Image') {
steps {
container('docker') {
sh '''
aws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin < AWS ECR URL >
docker build --build-arg -t < AWS ECR URL > --network=host .
'''
}
}
The result is the error that doesn't listen to the docker socket as i mention in version 1.24 Kubernetes doesnt support docker daemon anymore.
I would like to ask you how you deploy now in Kubernetes 1.24.
I read that there are some tools img, buildah, kaniko, or buildkit-cli-for-kubectl that don’t require Docker.
Can you recommend me any solution or help in this subject ?
We are using EKS from AWS.
Thank you
You can try Mirantis cri-dockerd, some explanations can be found here.

How to upload and download docker images using nexus registry/repository?

I was able to publish a Docker image using the jenkins pipeline, but not pull the docker image from the nexus.I used kaniko to build the image.
deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test-app
name: test-app
namespace: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: test-app
template:
metadata:
labels:
app: test-app
spec:
hostNetwork: false
containers:
- name: test-app
image: ip_adress/demo:0.1.0
imagePullPolicy: Always
resources:
limits: {}
imagePullSecrets:
- name: registrypullsecret
service.yml
apiVersion: v1
kind: Service
metadata:
labels:
app: test-app
name: test-app-service
namespace: jenkins
spec:
ports:
- nodePort: 32225
port: 8081
protocol: TCP
targetPort: 8081
selector:
app: test-app
type: NodePort
Jenkins pipeline main script
stage ('Build Image'){
container('kaniko'){
script {
sh '''
/kaniko/executor --dockerfile `pwd`/Dockerfile --context `pwd` --destination="$ip_adress:8082/demo:0.1.0" --insecure --skip-tls-verify
'''
}
stage('Kubernetes Deployment'){
container('kubectl'){
withKubeConfig([credentialsId: 'kube-config', namespace:'jenkins']){
sh 'kubectl get pods'
sh 'kubectl apply -f deployment.yml'
sh 'kubectl apply -f service.yml'
}
I've created a dockerfile of a Spring boot Java application. I've sent the image to Nexus using the Jenkins pipeline, but I can't deploy it.
kubectl get pod -n jenkins
test-app-... 0/1 ImagePullBackOff
kubectl describe pod test-app-.....
Error from server (NotFound): pods "test-app-.." not found
docker pull $ip_adress:8081/repository/docker-releases/demo:0.1.0 ```
Error response from daemon: Get "https://$ip_adress/v2/": http:server
gave HTTP response to HTTPS client
ip adress: private ip address
How can I send as http?
First of all try to edit /etc/containerd/config.toml and add your registry ip:port like this { "insecure-registries": ["172.16.4.93:5000"] }
if there was still a problem, add your nexus registry credential to yaml kubernetes file like link below
https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
If we want to use a private registry to pull the images in kubernetes we need to configure the registry endpoint and credentials as a secret and use it in pod deployment configuration.
Note: The secrets must have to be in the same namespace as Pod
Refer this official k8 document to know more details about configuring private registry in Kubernetes
In your case you are using secret registrypullsecret . So check the secret one more time whether it is configured properly or not. If not, try following the documentation mentioned above.

Permission denied with Docker in Docker in Atlassian Bamboo Server

I'm trying to build a docker image using DIND with Atlassian Bamboo.
I've created the deployment/ StatefulSet as follows:
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: bamboo
name: bamboo
namespace: csf
spec:
replicas: 1
serviceName: bamboo
revisionHistoryLimit: 10
selector:
matchLabels:
app: bamboo
template:
metadata:
creationTimestamp: null
labels:
app: bamboo
spec:
containers:
- image: atlassian/bamboo-server:latest
imagePullPolicy: IfNotPresent
name: bamboo-server
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
securityContext:
privileged: true
volumeMounts:
- name: bamboo-home
mountPath: /var/atlassian/application-data/bamboo
- mountPath: /opt/atlassian/bamboo/conf/server.xml
name: bamboo-server-xml
subPath: bamboo-server.xml
- mountPath: /var/run
name: docker-sock
volumes:
- name: bamboo-home
persistentVolumeClaim:
claimName: bamboo-home
- configMap:
defaultMode: 511
name: bamboo-server-xml
name: bamboo-server-xml
- name: docker-sock
hostPath:
path: /var/run
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
Note that I've set privileged: true in securityContext to enable this.
However, when trying to run docker images, I get a permission error:
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/create: dial unix /var/run/docker.sock: connect: permission denied.
See '/var/atlassian/application-data/bamboo/appexecs/docker run --help'
Am I missing something wrt setting up DIND?
The /var/run/docker.sock file on the host system is owned by a different user than the user that is running the bamboo-server container process.
Without knowing any details about your cluster, I would assume docker runs as 'root' (UID=0). The bamboo-server runs as 'bamboo', as can be seen from its Dockerfile, which will normally map to a UID in the 1XXX range on the host system. As these users are different and the container process did not receive any specific permissions over the (host) socket, the error is given.
So I think there are two approaches possible:
Or the container process continues to run as the 'bamboo' user, but is given sufficient permissions on the host system to access /var/run/docker.sock. This would normally mean adding the UID the bamboo user maps to on the host system to the docker group on the host system. However, making changes to the host system might or might not be an option depending on the context of your cluster, and is tricky in a cluster context because the pod could migrate to a different node where the changes were not applied and/or the UID changes.
Or the container is changed as to run as a sufficiently privileged user to begin with, being the root user. There are two ways to accomplish this: 1. you extend and customize the Atlassian provided base image to change the user or 2. you override the user the container runs as at run-time by means of the 'runAsUser' and 'runAsGroup' securityContext instructions as specified here. Both should be '0'.
As mentioned in the documentation here
If you want to run docker as non-root user then you need to add it to the docker group.
Create the docker group if it does not exist
$ sudo groupadd docker
Add your user to the docker group.
$ sudo usermod -aG docker $USER
Log out and log back in so that your group membership is re-evaluated.
$ newgrp docker
Verify that you can run docker commands without sudo
$ docker run hello-world
If that doesn't help you can change the permissions of docker socket to be able to connect to the docker daemon /var/run/docker.sock.
sudo chmod 666 /var/run
A better way to handle this is to run a sidecar container - docker:dind, and export DOCKER_HOST=tcp://dind:2375 in the main Bamboo container. This way you will invoke Docker in a dind container and won't need to mount /var/run/docker.sock

How to start the cloudwatch agent in container?

From the docker hub there is an image which is maintained by amazon.
Any one know how to configure and start the container as I cannot find any documentation
I got this working! I was having the same issue with you when you see Reading json config file path: /opt/aws/amazon-cloudwatch-agent/bin/default_linux_config.json ... Cannot access /etc/cwagentconfig: lstat /etc/cwagentconfig: no such file or directoryValid Json input schema.
What you need to do is put your config file in /etc/cwagentconfig. A functioning dockerfile:
FROM amazon/cloudwatch-agent:1.230621.0
COPY config.json /etc/cwagentconfig
Where config.json is some cloudwatch agent configuration, such as given by LinPy's answer.
You can ignore the warning about /opt/aws/amazon-cloudwatch-agent/bin/default_linux_config.json, or you can also COPY the config.json file to that location in the dockerfile as well.
I will also share how I found this answer:
I needed this run in ECS as a sidecar, and I could only find docs on how to run it in kubernetes. Following this documentation: https://docs.aws.amazon.com/en_pv/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-StatsD.html I decided to download all the example k8s manifests, when I saw this one:
apiVersion: v1
kind: Pod
metadata:
namespace: default
name: amazonlinux
spec:
containers:
- name: amazonlinux
image: amazonlinux
command: ["/bin/sh"]
args: ["-c", "sleep 300"]
- name: cloudwatch-agent
image: amazon/cloudwatch-agent
imagePullPolicy: Always
resources:
limits:
cpu: 200m
memory: 100Mi
requests:
cpu: 200m
memory: 100Mi
volumeMounts:
- name: cwagentconfig
mountPath: /etc/cwagentconfig
volumes:
- name: cwagentconfig
configMap:
name: cwagentstatsdconfig
terminationGracePeriodSeconds: 60
So I saw that the volume mount cwagentconfig mounts to /etc/cwagentconfig and that's from the cwagentstatsdconfig configmap, and that's just the json file.
You just to run the container with log-opt, as the log agent is the main process of the container.
docker run --log-driver=awslogs --log-opt awslogs-region=us-west-2 --log-opt awslogs-group=myLogGroup amazon/cloudwatch-agent
You can find more details here and here.
I do not know why you need an agent in a container, but the best practice is to send each container log directly to cloud watch using aws log driver.
Btw this is entrypoint of the container.
"Entrypoint": [
"/opt/aws/amazon-cloudwatch-agent/bin/start-amazon-cloudwatch-agent"
],
All you need to call
/opt/aws/amazon-cloudwatch-agent/bin/start-amazon-cloudwatch-agent
Here is how I got it working in our Docker containers without systemctl or System V init.
This is from official Documentation:
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:configuration-file-path -s
here the Docs:
https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-commandline-fleet.html#start-CloudWatch-Agent-EC2-commands-fleet
Installation path may be different, but that is how the agent is started as per docs.

Permission denied when connecting to docker daemon on jenkinsci/blueocean image deployed to kubernetes

Summary
Running a declarative pipeline job in jenkins which was deployed to a kubernetes cluster fails when using the docker agent with the following error:
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.39/images/create?fromImage=node&tag=10.15.1: dial unix /var/run/docker.sock: connect: permission denied
How can I solve this permission error in the kubernetes declaration?
Background
We have a jenkins server which was deployed to a kubernetes cluster using the jenkinsci/blueocean image. The kubernetes declaration as done as follows:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: jenkins-master
spec:
replicas: 1
template:
metadata:
labels:
app: jenkins-master
spec:
terminationGracePeriodSeconds: 10
serviceAccountName: jenkins
containers:
- name: jenkins-master
image: jenkinsci/blueocean
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 8080
- name: jnlp-port
containerPort: 50000
env:
- name: "JAVA_OPTS"
value: "-Dorg.jenkinsci.plugins.durabletask.BourneShellScript.HEARTBEAT_CHECK_INTERVAL=3600"
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
- name: docker-socket
mountPath: /var/run/docker.sock
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: File
We then declare a declarative pipeline jenkins job as follows:
pipeline {
agent {
docker {
image 'node:10.15.1'
label 'master'
}
}
stages {
stage('Checkout source code') {
steps {
checkout scm
}
}
stage('Build project') {
steps {
sh 'npm install'
sh 'npm run compile'
}
}
stage('Run quality assurance') {
steps {
sh 'npm run style:check'
sh 'npm run test:coverage'
}
}
}
}
This job fails with the aforementioned error. My suspicion is that the docker socket was mounted into the system, but the user running the job does not have permission to execute the socket. I, however, cannot add the user to the group in the created pod using sudo usermod -a -G docker $USER since the pod will be recreated upon each redeploy.
Questions
Is it possible to mount the docker volume using the correct user in the kubernetes declaration?
Can I declare the pipeline differently, if it is not possible to set up the permission in the kubernetes declaration?
Is there some other solution which I have not thought about?
Thanks.
I, however, cannot add the user to the group in the created pod using
sudo usermod -a -G docker $USER since the pod will be recreated upon
each redeploy.
Actually, you can.
Define a usermod command for your container in the deployment yaml, e.g
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: jenkins-master
spec:
replicas: 1
template:
metadata:
labels:
app: jenkins-master
spec:
terminationGracePeriodSeconds: 10
serviceAccountName: jenkins
containers:
- name: jenkins-master
image: jenkinsci/blueocean
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 8080
- name: jnlp-port
containerPort: 50000
env:
- name: "JAVA_OPTS"
value: "-Dorg.jenkinsci.plugins.durabletask.BourneShellScript.HEARTBEAT_CHECK_INTERVAL=3600"
- name: "USER"
value: "Awemo"
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
- name: docker-socket
mountPath: /var/run/docker.sock
command: ["/bin/sh"]
args: ["-c", "usermod -aG docker $USER"]
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: File
So, whenever a new pod is created, a user will be added to the docker usergroup

Resources