๐ Using Docker#
See also
Note
Installing Portainer
docker volume create portainer_data
docker run -d -p 9000:9000 --name portainer --restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data portainer/portainer
First Steps#
The Basic Commands#
Tip
docker run |
|
-h, โhostname string |
Container host name |
-i, โinteractive |
Keep STDIN open even if not attached |
โname string |
Assign a name to the container |
-t, โtty |
Allocate a pseudo-TTY |
Use awk to display options.
awk 'BEGIN{print "docker run"}$1 ~ /^(--name|-[ith])/{print $0}' <(docker run --help)
Run a command in a new container.
docker run -h CONTAINER -i -t debian /bin/bash
docker inspect quirky_jackson --format {{.NetworkSettings.IPAddress}}
docker diff quirky_jackson
docker logs quirky_jackson
docker exec -it 4006e491063e /bin/bash
docker rm -v $(docker ps -aq -f status=exited)
Create a new image from a containerโs changes.
docker run -it --name cowsay --hostname cowsay debian bash
root@cowsay:/# history
apt update
apt install fortune cowsay -y
docker ps -a
docker diff cowsay
docker commit cowsay test/cowsayimage
docker images
docker run test/cowsayimage /usr/games/cowsay "Moo"
Building Images from Dockerfiles#
Tip
docker build |
|
โno-cache |
Do not use cache when building the image |
โrm |
Remove intermediate containers after a successful build |
-f, โfile string |
Name of the Dockerfile (Default is โPATH/Dockerfileโ) |
-t, โtag list |
Name and optionally a tag in the โname:tagโ format |
./cowsay
โโโ [-rw-r--r--] Dockerfile
โโโ [-rwxr-xr-x] entrypoint.sh
Create Dockerfile.
FROM debian:latest
RUN apt-get update && apt-get install -y cowsay fortune
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
VOLUME /data
Create entrypoint.sh.
#!/bin/bash
if [ $# -eq 0 ]; then
/usr/games/fortune | /usr/games/cowsay
else
/usr/games/cowsay "$@"
fi
Build an image from Dockerfile.
cd cowsay/
docker build -t test/cowsay-dockerfile .
docker run test/cowsay-dockerfile "Moo"
_____
< Moo >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Working with Registries#
The official Docker registry is the Docker Hub .
registry/repository:tag
Registry |
a service responsible for hosting and distributing images |
Repository |
a collection of related images |
Tag |
an alphanumeric identifier attached to images |
Note
Log in to default Docker registry.
docker login -u guisam
Login Succeeded
Pull/push an image or a repository from a registry.
docker pull amouat/revealjs:latest
docker push guisam/cowsay
Using the Redis Official Image#
Tip
docker run |
|
-d, โdetach |
run container in background and print container ID |
โrm |
automatically remove the container when it exits |
-v, โvolume list |
bind mount a volume |
โlink list |
add link to another container |
The โlink myredis:redis argument connect the new container redis to the existing myredis container.
Pull redis image, run in background.
docker pull redis
docker run --name myredis -d redis
Link redis container, add/save redis data.
docker run --rm -it --link myredis:redis redis /bin/bash
root@bc6f6085859b:/data# redis-cli -h redis -p 6379
redis:6379> ping
PONG
redis:6379> set "abc" 123
OK
redis:6379> save
OK
redis:6379> get "abc"
"123"
Get redis backup.
docker run --rm --volumes-from myredis -v $(pwd)/backup:/backup \
debian cp /data/dump.rdb /backup/
backup
โโโ dump.rdb
Docker Fundamentals#
The Docker Architecture#
Docker registries store and distribute images. The default registry is the Docker Hub.
Docker daemon, which is responsible for creating, running, and monitoring containers, as well as building and storing images
Docker client is on the left-hand side and is used to talk to the Docker daemon. By default, this happens over a Unix domain socket.
Underlying Technologies#
Surrounding Technologies#
Tools |
|
Compose |
|
Kitematic |
|
Machine |
|
Swarm |
|
Networking |
|
Calico |
https://docs.projectcalico.org/archive/v3.17/about/about-calico |
Flannel |
|
Weave |
|
Service discovery |
|
Consul |
|
Etcd |
|
Registrator |
|
Skydns |
|
Orchestration and cluster management |
|
Kubernetes |
|
Marathon |
|
Mesos |
|
How Images Get Built#
The Build Context#
The docker build command requires a Dockerfile and a build context. The build command docker build -t test/cowsay-dockerfile . in โBuilding Images from Dockerfilesโ sets the context to โ.โ , the current working directory.
Tip
Use a .dockerignore File
.git
*/.git
*/*/.git
Image Layers#
Dockerfile results in a new image layer. This means that while you can start long- lived processes, such as databases or SSH daemons in a RUN instruction, it must be launched from an ENTRYPOINT or CMD instruction.
Show the history of an image.
docker history test/cowsay-dockerfile:latest
Caching#
Docker caches each layer in order to speed up the building of images.
- --no-cache
Do not use cache when building the image
You can also add or change an instruction to invalidate the cache.
ENV UPDATED_ON "14:12 17 February 2015"
Base Images#
A base image has FROM scratch in its Dockerfile.
Create Dockerfile.
FROM scratch
ADD hello /
CMD ["/hello"]
Tip
cat hello.c
#include <stdio.h>
int main() {
printf("hello from docker container\n");
return 0;
}
gcc -o hello -static hello.c
Build and run hello.
docker build -t test/hello .
docker run --rm test/hello
A parent image is the image that your image is based on.
FROM debian:buster
Dockerfile Instructions#
ADD |
copies files from the build context or remote URLs into the image |
CMD |
runs the given instruction when the container is started |
COPY |
used to copy files from the build context into the image |
ENTRYPOINT |
sets an executable to be run when the container starts |
ENV |
sets environment variables inside the image |
EXPOSE |
indicates to Docker that the container will listen on the given port(s) |
FROM |
sets the base image for the Dockerfile |
MAINTAINER |
sets the โAuthorโ metadata |
ONBUILD |
specifies an instruction to be executed later, when the image is used |
RUN |
runs the given instruction inside the container and commits the result |
USER |
sets the user (by name or UID) |
VOLUME |
declares the specified file or directory to be a volume |
WORKDIR |
sets the working directory |
Connecting Containers to the World#
Tip
docker run |
|
-p, โpublish list |
Publish a containerโs port(s) to the host |
-P, โpublish-all |
Publish all exposed ports to random ports |
docker run --name mynginx -d -p 8080:80 nginx
docker port mynginx
ID=$(docker run -d -P nginx)
echo $ID
docker port $ID
curl -I localhost:32768
Linking Containers#
Links are initialized by giving the argument โlink CONTAINER:ALIAS to docker run , where CONTAINER is the name of the link container and ALIAS is a local name used inside the master container to refer to the link container.
docker run --name myredis -d -p 6379:6379 redis
docker run --link myredis:redis debian env
docker run --rm -it --link myredis:redis debian /bin/bash
Managing Data with Volumes and Data Containers#
The three different ways to initialize volumes#
Declare a volume at runtime with the -v flag.
docker run -it --name container-test -h CONTAINER -v /data debian /bin/bash
docker inspect -f {{.Mounts}} container-test
sudo touch /var/lib/docker/volumes/be24.../_data/test-file
docker exec -it container-test /bin/bash
root@CONTAINER:/# ls /data/
test-file
Use the VOLUME instruction in a
Dockerfile.
FROM debian:buster
VOLUME /data
Using the format -v HOST_DIR:CONTAINER_DIR.
mkdir data
touch data/test-file
docker run --rm -v $PWD/data:/data debian ls /data
Data Containers#
data containers are containers whose sole purpose is to share data between other containers.
docker run --name dbdata postgres echo "Data-only container for postgres"
docker run -d --volumes-from dbdata --name db1 postgres
Common Docker Commands#
The run Command#
- -a, --attach list
Attach to STDIN, STDOUT or STDERR
- -d, --detach
Run container in background and print container ID
- -e, --env list
Set environment variables
- --expose list
Expose a port or a range of ports
- -h, --hostname string
Container host name
- -i, --interactive
Keep STDIN open even if not attached
- --link list
Add link to another container
- --name string
Assign a name to the container
- -p, --publish list
Publish a containerโs port(s) to the host
- -P, --publish-all
Publish all exposed ports to random ports
- --restart string
Restart policy to apply when a container exits (default โnoโ)
- --rm
Automatically remove the container when it exits
- -t, --tty
Allocate a pseudo-TTY
- -v, --volume list
Bind mount a volume
- --volumes-from list
Mount volumes from the specified container(s)
Tip
awk 'BEGIN { printf "%s\n", "The run Command"
printf "%s\n", "---------------" }
$1 ~ /^(-[aditehvpP]|--(expose|link|volumes-from|name|no-cache|restart|rm)$)/{print $0}
END { "date" | getline now
close("date")
printf "\nreported %s\n", now }' <(docker run --help)
Managing Containers#
attach |
Attach local standard input, output, and error streams to a running container |
cp |
Copy files/folders between a container and the local filesystem |
create |
Create a new container |
exec |
Run a command in a running container |
kill |
Kill one or more running containers |
pause |
Pause all processes within one or more containers |
restart |
Restart one or more containers |
rm |
Remove one or more containers |
start |
Start one or more stopped containers |
stop |
Stop one or more running containers |
unpause |
Unpause all processes within one or more containers |
ID=$(docker run -d debian sh -c "while true; do echo 'tick'; sleep 1; done;")
docker attach $ID
Docker Info#
info |
Display system-wide information |
help |
Prints usage and help information |
version |
Show the Docker version information |
Container Info#
diff |
Inspect changes to files or directories on a containerโs filesystem |
events |
Get real time events from the server |
inspect |
Return low-level information on Docker objects |
logs |
Fetch the logs of a container |
port |
List port mappings or a specific mapping for the container |
ps |
List containers |
top |
Display the running processes of a container |
Dealing with Images#
build |
Build an image from a Dockerfile |
commit |
Create a new image from a containerโs changes |
export |
Export a containerโs filesystem as a tar archive |
history |
Show the history of an image |
images |
List images |
import |
Import the contents from a tarball to create a filesystem image |
load |
Load an image from a tar archive or STDIN |
rmi |
Remove one or more images |
save |
Save one or more images to a tar archive (streamed to STDOUT by default) |
tag |
Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE |
Using the Registry#
login |
Log in to a Docker registry |
logout |
Log out from a Docker registry |
pull |
Pull an image or a repository from a registry |
push |
Push an image or a repository to a registry |
search |
Search the Docker Hub for images |
Using Docker in Development#
Say โHello World!โ#
identidock
โโโ [drwxr-xr-x] app
โย ย โโโ [-rw-r--r--] identidock.py
โโโ [-rwxr-xr-x] cmd.sh
โโโ [-rw-r--r--] Dockerfile
Create identidock.py.
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello Docker!\n'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
Create cmd.sh.
#!/bin/bash
set -e
if [ "$ENV" = 'DEV' ]; then
echo "Running Development Server"
exec python "identidock.py"
else
echo "Running Production Server"
exec uwsgi --http 0.0.0.0:9090 --wsgi-file /app/identidock.py \
--callable app --stats 0.0.0.0:9191
fi
Create Dockerfile.
FROM python:latest
RUN groupadd -r uwsgi && useradd -r -g uwsgi uwsgi
RUN pip install Flask uWSGI
WORKDIR /app
COPY app /app
COPY cmd.sh /
EXPOSE 9090 9191
USER uwsgi
CMD ["/cmd.sh"]
Build image and run.
docker build -t identidock .
docker run --name hello -d -p 9090-9091:9090-9091 -v "$(pwd)"/app:/app identidock:latest
docker port hello
docker inspect -f {{.Mounts}} hello
Run in dev mode.
docker run --rm -e "ENV=DEV" -p 5000:5000 identidock
Danger
Always Set a USER
Itโs important to set the USER statement in all your Dockerfiles. If not set and an attacker break the container, he will have root access to the host machine.
Automating with Compose#
identidock
โโโ [drwxr-xr-x] app
โย ย โโโ [-rw-r--r--] identidock.py
โโโ [-rwxr-xr-x] cmd.sh
โโโ [-rw-r--r--] docker-compose.yml
โโโ [-rw-r--r--] Dockerfile
Create docker-compose.yml.
identidock:
build: .
ports:
- "7373:5000"
environment:
ENV: DEV
volumes:
- ./app:/app
Create and start container.
docker-compose up
The Compose Workflow#
build |
Build or rebuild services |
logs |
View output from containers |
ps |
List containers |
rm |
Remove stopped containers |
run |
Run a one-off command |
stop |
Stop services |
up |
Create and start containers |
- -f, --file FILE
Specify an alternate compose file
- -p, --project-name NAME
Specify an alternate project name
Creating a Simple Web App#
Creating a Basic Web Page#
Update identidock/app/identidock.py.
app = Flask(__name__)
+default_name = 'Gui Sam'
+
@app.route('/')
-def hello_world():
- return 'Hello Docker!\n'
+def get_identicon():
+ name = default_name
+ header = '<html><head><title>Identidock</title></head><body>'
+ body = '''
+ <form method="POST">
+ Hello <input type="text" name="name" value="{}">
+ <input type="submit" value="submit">
+ </form>
+ <p>You look like a:
+ <img src="/monster/monster.png"/>
+ '''.format(name)
+ footer = '</body></html>'
+
+ return header + body + footer
if __name__ == '__main__':
Taking Advantage of Existing Images#
Update
identidock/app/identidock.py.
-from flask import Flask
+from flask import Flask, Response, request
+import requests
+import hashlib
app = Flask(__name__)
+salt = "UNIQUE_SALT"
default_name = 'Gui Sam'
-@app.route('/')
-def get_identicon():
+@app.route('/', methods=['GET', 'POST'])
+def mainpage():
+
name = default_name
+ if request.method == 'POST':
+ name = request.form['name']
+
+ salted_name = salt + name
+ name_hash = hashlib.sha256(salted_name.encode()).hexdigest()
header = '<html><head><title>Identidock</title></head><body>'
- body = '''
- <form method="POST">
- Hello <input type="text" name="name" value="{}">
- <input type="submit" value="submit">
- </form>
- <p>You look like a:
- <img src="/monster/monster.png"/>
- '''.format(name)
+ body = '''<form method="POST">
+ Hello <input type="text" name="name" value="{0}">
+ <input type="submit" value="submit">
+ </form>
+ <p>You look like a:
+ <img src="/monster/{1}"/>
+ '''.format(name, name_hash)
footer = '</body></html>'
return header + body + footer
+@app.route('/monster/<name>')
+def get_identicon(name):
+
+ r = requests.get('http://dnmonster:8080/monster/' + name + '?size=80')
+ image = r.content
+
+ return Response(image, mimetype='image/png')
+
if __name__ == '__main__':
Update Dockerfile.
RUN groupadd -r uwsgi && useradd -r -g uwsgi uwsgi
-RUN pip install Flask uWSGI requests
+RUN pip install Flask uWSGI
WORKDIR /app
Rebuild image and run identidock and dnmonster.
docker build -t identidock .
docker run -d --name dnmonster amouat/dnmonster:1.0
docker run -d -p 5000:5000 -e "ENV=DEV" --link dnmonster:dnmonster identidock
Update
docker-compose.yml.
volumes:
- ./app:/app
+ links:
+ - dnmonster
+
+dnmonster:
+ image: amouat/dnmonster:1.0
Tip
docker-compose up |
|
-d, โdetach |
Detached mode: Run containers in the background |
โbuild |
Build images before starting containers |
Launch webapp with compose.
docker-compose up --build -d
Add Some Caching#
Update identidock/app/identidock.py.
import hashlib
+import redis
app = Flask(__name__)
+cache = redis.StrictRedis(host='redis', port=6379, db=0)
salt = "UNIQUE_SALT"
def get_identicon(name):
- r = requests.get('http://dnmonster:8080/monster/' + name + '?size=80')
- image = r.content
+ image = cache.get(name)
+ if image is None:
+ print ("Cache miss", flush=True)
+ r = requests.get('http://dnmonster:8080/monster/' + name + '?size=80')
+ image = r.content
+ cache.set(name, image)
return Response(image, mimetype='image/png')
Update Dockerfile.
RUN groupadd -r uwsgi && useradd -r -g uwsgi uwsgi
-RUN pip install Flask uWSGI requests
+RUN pip install Flask uWSGI requests redis
WORKDIR /app
Update docker-compose.yml.
- dnmonster
+ - redis
dnmonster:
image: amouat/dnmonster:1.0
+redis:
+ image: redis:latest
docker-compse down
docker-compose up --build -d
docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------------------------
identidock_dnmonster_1 npm start Up 8080/tcp
identidock_identidock_1 /cmd.sh Up 0.0.0.0:5000->5000/tcp, 9090/tcp, 9191/tcp
identidock_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
source: tgz
Image Distribution#
Image and Repository Naming#
Image names and tags are set when building the image or by using the docker tag command.
docker build -t "identidock:0.1" .
docker tag "identidock:0.1" "guisam/identidock:0.1"
The Docker Hub#
Tag and push on Docker Hub .
docker tag identidock:latest guisam/identidock:0.1
docker push guisam/identidock:0.1
Private Distribution#
Running Your Own Registry#
registry
โโโ certs
โย ย โโโ guigui-002.cnf
โย ย โโโ guigui-002.crt
โย ย โโโ guigui-002.key
โโโ registry_data
Create guigui-002.cnf.
[req]
default_bits = 2048
prompt = no
default_md = sha256
x509_extensions = v3_req
distinguished_name = dn
[dn]
C = FR
ST = Neuf-Quatre
L = Ivry-sur-Seine
O = Guisam
emailAddress = toto@guisam.xyz
CN = guigui-002
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = guigui-002.guisam.xyz
DNS.2 = guigui-002.kapinfra.net
Generate a TLS certificate.
openssl req -new -x509 -newkey rsa:4096 -sha512 -nodes \
-keyout guigui-002.key -days 3560 \
-out guigui-002.crt -config guigui-002.cnf
Copy the certificate to each Docker daemon that will access the
registry to the file /etc/docker/certs.d/<registry_address>/<ca>.crt.
sudo mkdir -p /etc/docker/certs.d/guigui-002.guisam.xyz:443
sudo cp guigui-002.crt /etc/docker/certs.d/guigui-002.guisam.xyz:443
sudo systemctl restart docker.service
Note
Add the registry hostname in /etc/hosts if needed.
Run registry container.
docker run -d \
--restart=always \
--name registry \
-v "$(pwd)"/certs:/certs \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/guigui-002.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/guigui-002.key \
-p 443:443 \
-v "$(pwd)"/registry_data:/var/lib/registry \
registry:2
Create tag and push.
docker tag alpine:latest guigui-002.guisam.xyz:443/alpine:local
docker push guigui-002.guisam.xyz:443/alpine:local
Pull images from registry.
docker pull guigui-002.guisam.xyz:443/alpine:local
Manage registry with curl:
Check registry service.
curl -I -k https://guigui-002.guisam.xyz:443/v2/
HTTP/2 200
content-type: application/json; charset=utf-8
docker-distribution-api-version: registry/2.0
x-content-type-options: nosniff
content-length: 2
date: Fri, 13 Mar 2020 17:58:17 GMT
List registry catalog.
curl -k https://guigui-002.guisam.xyz:443/v2/_catalog
{"repositories":["alpine","identidock"]}
Check/get alpine:local image existence.
curl -I -k https://guigui-002.guisam.xyz:443/v2/alpine/manifests/local
HTTP/2 200
...
curl -k https://guigui-002.guisam.xyz:443/v2/alpine/manifests/local
Important
Reducing Image Size#
The total size of the image is the sum of all its layers.
.
โโโ Dockerfile1
โโโ Dockerfile2
Create Dockerfile1.
FROM debian:buster
RUN dd if=/dev/zero of=/bigfile count=1 bs=50MB
RUN rm /bigfile
Create Dockerfile2.
FROM debian:buster
RUN dd if=/dev/zero of=/bigfile count=1 bs=50MB \
&& rm /bigfile
Build the both containers.
docker build -f Dockerfile1 -t test/filetest1 .
docker build -f Dockerfile2 -t test/filetest2 .
Compare the containers images size.
docker images test/filetest1
REPOSITORY TAG IMAGE ID CREATED SIZE
test/filetest1 latest 77081a6d4e51 14 seconds ago 164MB
docker images test/filetest2
REPOSITORY TAG IMAGE ID CREATED SIZE
test/filetest2 latest dcd9a0ad691d 17 minutes ago 114MB
Compare the containers images history.
docker history test/filetest1
IMAGE CREATED CREATED BY SIZE
77081a6d4e51 2 minutes ago /bin/sh -c rm /bigfile 0B
98906ef412f3 2 minutes ago /bin/sh -c dd if=/dev/zero of=/bigfile countโฆ 50MB
971452c94376 2 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:e05e45c33042db4ecโฆ 114MB
docker history test/filetest2
IMAGE CREATED CREATED BY SIZE
dcd9a0ad691d 20 minutes ago /bin/sh -c dd if=/dev/zero of=/bigfile countโฆ 0B
971452c94376 2 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:e05e45c33042db4ecโฆ 114MB
Image Provenance#
See Content Trust .
Continuous Integration and Testing with Docker#
Adding Unit Tests to Identidock#
Create identidock/app/tests.py.
import unittest
import identidock
class TestCase(unittest.TestCase):
def setUp(self):
identidock.app.config["TESTING"] = True
self.app = identidock.app.test_client()
def test_get_mainpage(self):
page = self.app.post("/", data=dict(name="Moby Dock"))
assert page.status_code == 200
assert 'Hello' in str(page.data)
assert 'Moby Dock' in str(page.data)
def test_html_escaping(self):
page = self.app.post("/", data=dict(name='"><b>TEST</b><!--'))
assert '<b>' not in str(page.data)
if __name__ == '__main__':
unittest.main()
Rebuild and run unit tests.
docker build -t identidock .
docker run --rm identidock python tests.py
.F
======================================================================
FAIL: test_html_escaping (__main__.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 18, in test_html_escaping
assert '<b>' not in str(page.data)
AssertionError
----------------------------------------------------------------------
Ran 2 tests in 0.009s
FAILED (failures=1)
Update identidock.py to fix unit tests failure.
import redis
+import html
...
app = Flask(__name__)
if request.method == 'POST':
- name = request.form['name']
+ name = html.escape(request.form['name'], quote=True)
salted_name = salt + name
...
def get_identicon(name):
+ name = html.escape(name, quote=True)
image = cache.get(name)
Update cmd.sh to support automatic execution.
exec python "identidock.py"
+elif [ "$ENV" = 'UNIT' ]; then
+ echo "Running Unit Tests"
+ exec python "tests.py"
else
Rebuild and run.
docker build -t identidock .
docker run --rm -e ENV="UNIT" identidock
Running Unit Tests
..
----------------------------------------------------------------------
Ran 2 tests in 0.008s
OK
Creating a Jenkins Container#
Jenkins is a popular open source CI server. When we push changes to our identidock project, Jenkins will automatically check out the changes, build the new images, and run some tests against them (both our unit tests and some system tests).
Docker-In-Docker versus Socket Mounting#
In order to allow Docker container to build images:
mount the Docker socket from the host into the container;
or use Docker-in-Docker (DinD), where the Docker container can create its own โchildโ containers.
Note
Docker-in-Docker
docker run --rm --privileged -t -i -e LOG=file jpetazzo/dind
root@2144149fdb6a:/# docker run busybox echo "Hello New World!"
Create Jenkins image with Socket Mounting and Docker client installed#
Create identijenk directory.
.
โโโ identidock
โย ย โโโ ...
โโโ identijenk
โโโ Dockerfile
โโโ plugins.txt
Create identijenk files.
DockerfileFROM jenkins/jenkins:lts USER root RUN apt-get update \ && apt-get install -y apt-transport-https; \ echo "deb [arch=amd64] https://download.docker.com/linux/debian stretch stable" \ > /etc/apt/sources.list.d/docker.list; \ curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - \ && apt-get update \ && apt-get install -y docker-ce-cli sudo \ && rm -rf /var/lib/apt/lists/*; \ curl -L "https://github.com/docker/compose/releases/download/1.25.4/\ docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose; \ chmod +x /usr/local/bin/docker-compose; \ echo "jenkins ALL=NOPASSWD: ALL" >> /etc/sudoers COPY plugins.txt /usr/share/jenkins/plugins.txt RUN /usr/local/bin/plugins.sh /usr/share/jenkins/plugins.txt USER jenkins
plugins.txtcredentials:2.3.3 workflow-scm-step:2.9 apache-httpcomponents-client-4-api:4.5.10-2.0 trilead-api:1.0.5 ssh-credentials:1.18.1 script-security:1.71 jsch:0.1.55.2 structs:1.20 scm-api:2.6.3 git-client:3.2.1 git:4.2.2 greenballs:latest mailer:1.30 display-url-api:2.3.2
4. Build identijenk image and create jenkins-data container. Then run jenkins container with socket mount.
docker build -t identijenk .
docker run --name jenkins-data identijenk echo "Jenkins Data Container"
docker run -d --name jenkins -p 8080:8080 \
--volumes-from jenkins-data \
-v /var/run/docker.sock:/var/run/docker.sock \
identijenk
Tip
Check SSH tunnels existence.
awk '{ if ($5 == "ssh" && $6 == "-L")
{ $2 = $3 = $4 = ""
$8 = gensub(/(.*)(@guigui-002)(.+)/, "<user>\\2", "g", $8)
print $0 }}' <(ps ax)
891164 ssh -L 8080:localhost:8080 <user>@guigui-002 -f -N
101614 ssh -L 7373:localhost:7373 <user>@guigui-002 -f -N
Kill existing SSH tunnels.
awk '{ if ($5 == "ssh" && $6 == "-L")
{ print $1 }}' <(ps ax) | xargs kill
Check docker service in jenkins container and web interface.
docker exec -it jenkins /bin/bash
jenkins@92eb4708c136:/$ sudo docker ps -a
CONTAINER ID IMAGE [...] NAMES
92eb4708c136 identijenk [...] jenkins
d4c8bbf78fc4 identijenk [...] jenkins-data
917cbd9b014c identidock_identidock [...] identidock_identidock_1
1c1f1381620c redis:latest [...] identidock_redis_1
d1a5398cd267 amouat/dnmonster:1.0 [...] identidock_dnmonster_1
055dac63eda9 registry:2 [...] registry
jenkins@92eb4708c136:/$ sudo docker run --rm test/hello
hello from docker container
Jenkins web interface#