Difference between revisions of "Small Docker Notes"
(Created page with "Note - ''vm'' and ''container'' is used below interchangeably. == Installation and Verification == <pre> # install Docker $ curl -fsSL https://get.docker.com/ | sh # add...") |
|||
(2 intermediate revisions by one user not shown) | |||
Line 13: | Line 13: | ||
$ docker run hello-world | $ docker run hello-world | ||
# this should download image from docker hub, and print "Hello from Docker." message</pre> | # this should download image from docker hub, and print "Hello from Docker." message</pre> | ||
+ | |||
+ | As a rule of thumb: <tt>`docker`</tt> is the "super-system" used to manage docker containers (and more). <tt>`docker-compose`</tt> does the same tasks as ''docker'', but only on containers defined in ''docker-compose.yml'' file in current directory. So, <tt>`docker ps -a`</tt> will list all containers, <tt>`docker-compose ps`</tt> will list info about all containers from local ''docker-compose.yml'' file. | ||
+ | |||
+ | If something goes wrong, check | ||
+ | $ docker-compose logs | ||
+ | or | ||
+ | $ docker logs ''container-id'' | ||
== Stack in Separate Containers == | == Stack in Separate Containers == | ||
Line 25: | Line 32: | ||
First, create config file for docker compose, called ''docker-compose.yml'' . | First, create config file for docker compose, called ''docker-compose.yml'' . | ||
− | |||
− | |||
− | |||
<pre>nginx: | <pre>nginx: | ||
# based on latest nginx image | # based on latest nginx image | ||
Line 77: | Line 81: | ||
<pre>FROM nginx:latest | <pre>FROM nginx:latest | ||
COPY ./default.conf /etc/nginx/conf.d/default.conf</pre> | COPY ./default.conf /etc/nginx/conf.d/default.conf</pre> | ||
+ | |||
+ | See [https://docs.docker.com/engine/reference/builder/ official Dockerfile reference] for details. | ||
This will build vm from ''nginx:latest'' image, and copy ''./docker/nginx/default.conf'' to ''/etc/nginx/conf.d/'' in the vm. Create this file with the following content: | This will build vm from ''nginx:latest'' image, and copy ''./docker/nginx/default.conf'' to ''/etc/nginx/conf.d/'' in the vm. Create this file with the following content: | ||
Line 141: | Line 147: | ||
...</pre> | ...</pre> | ||
− | If you get "''Service 'nginx' needs to be built, but --no-build was passed.''" message, run <tt>`docker-compose build`</tt> and <tt>`docker-compose up -d`</tt>. Verify all is OK and started: | + | If you get "''Service 'nginx' needs to be built, but --no-build was passed.''" message, run <tt>`docker-compose build`</tt> and again <tt>`docker-compose up -d`</tt>. Verify all is OK and started: |
− | <pre>docker ps | + | <pre>$ docker ps |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | ||
fd04b796e34f dockertut_nginx "nginx -g 'daemon off" 4 seconds ago Up 4 seconds 443/tcp, 0.0.0.0:8080->80/tcp dockertut_nginx_1 | fd04b796e34f dockertut_nginx "nginx -g 'daemon off" 4 seconds ago Up 4 seconds 443/tcp, 0.0.0.0:8080->80/tcp dockertut_nginx_1 | ||
Line 198: | Line 204: | ||
and check that ''localhost:8080'' is still responding. | and check that ''localhost:8080'' is still responding. | ||
− | + | === Adding MySQL === | |
+ | |||
+ | Update the 'php' section: | ||
+ | <pre>php: | ||
+ | build: | ||
+ | ./docker/php/ | ||
+ | expose: | ||
+ | - 9000 | ||
+ | links: | ||
+ | - mysql | ||
+ | volumes_from: | ||
+ | - app</pre> | ||
+ | |||
+ | And add the following: | ||
+ | <pre>mysql: | ||
+ | image: mysql:latest | ||
+ | volumes_from: | ||
+ | - mysqldata | ||
+ | # set environment variables | ||
+ | environment: | ||
+ | MYSQL_ROOT_PASSWORD: secret | ||
+ | MYSQL_DATABASE: test | ||
+ | MYSQL_USER: test | ||
+ | MYSQL_PASSWORD: test | ||
+ | |||
+ | mysqldata: | ||
+ | image: mysql:latest | ||
+ | volumes: | ||
+ | # the /var/lib/mysql will be present in container, and "somewhere" on host | ||
+ | - /var/lib/mysql | ||
+ | command: "true"</pre> | ||
+ | |||
+ | And, create ''./docker/php/Dockerfile'': | ||
+ | <pre>FROM php:5.5-fpm | ||
+ | RUN docker-php-ext-install pdo_mysql</pre> | ||
+ | |||
+ | Now we're all set to <tt>`docker-compose build`</tt> and <tt>`docker-compose up -d`</tt>. Let's check what containers we have now: | ||
+ | <pre>$ docker ps -a | ||
+ | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | ||
+ | e43265be9680 dockertut_nginx "nginx -g 'daemon off" 16 seconds ago Up 14 seconds 443/tcp, 0.0.0.0:8080->80/tcp dockertut_nginx_1 | ||
+ | 48cd3b544fb1 dockertut_php "php-fpm" 19 seconds ago Up 17 seconds 9000/tcp dockertut_php_1 | ||
+ | 0e4f40d9ae8b mysql:latest "docker-entrypoint.sh" 21 seconds ago Up 20 seconds 3306/tcp dockertut_mysql_1 | ||
+ | 963440e29d89 mysql:latest "docker-entrypoint.sh" 22 seconds ago Exited (0) 20 seconds ago dockertut_mysqldata_1 | ||
+ | 1458644df104 php:5.5-fpm "true" 4 minutes ago Exited (0) 4 minutes ago dockertut_app_1</pre> | ||
+ | |||
+ | Now that all is set up, we can check where did docker mount the folder on host, that is seen as ''/var/lib/mysql'' in ''mysqldata'' instance: | ||
+ | <pre>$ docker inspect dockertut_mysqldata_1 | ||
+ | ... | ||
+ | "Mounts": [ | ||
+ | { | ||
+ | "Name": "d1352deaff99b25ee68bc53c07150b12b5eb7028b6182f1c97f71f7e21c8ee1d", | ||
+ | "Source": "/var/lib/docker/volumes/d1352deaff99b25ee68bc53c07150b12b5eb7028b6182f1c97f71f7e21c8ee1d/_data", | ||
+ | "Destination": "/var/lib/mysql", | ||
+ | ...</pre> | ||
+ | The ''Source'' is the folder on host that docker mounted as ''Destination'' in VM. | ||
+ | |||
+ | If you want all volumes removed when deleting docker container, use | ||
+ | $ docker rm -v ''container-id'' | ||
+ | Otherwise, the volumes will stay on your disk, taking up space. | ||
+ | |||
+ | You can also list all volumes registered by docker: | ||
+ | $ docker volume ls | ||
+ | and use this to remove all "dangling" volumes: | ||
+ | $ docker volume rm $(docker volume ls -qf dangling=true) | ||
+ | |||
+ | Let's check if mysql is up and running, through terminal. You can open interactive terminal in image like this: | ||
+ | <pre>$ docker exec -it dockertut_mysql_1 /bin/bash | ||
+ | root@0e4f40d9ae8b:/# mysql -u root -p | ||
+ | Enter password: | ||
+ | Welcome to the MySQL monitor. Commands end with ; or \g. | ||
+ | ... | ||
+ | mysql> _</pre> | ||
+ | Neat, huh? The ''-i'' means to run interactive command, ''-t'' to run in terminal. | ||
+ | |||
+ | == Manage Docker as non-root User == | ||
+ | |||
+ | By creating <tt>docker</tt> group, and adding users to it, you may select users that can manage docker daemon and processes: | ||
+ | |||
+ | <pre>$ sudo groupadd docker | ||
+ | $ sudo usermod -aG docker $USER</pre> | ||
+ | |||
+ | Afterwards, restart your machine (or, log out and in, and stop and start the docker daemon), and you should be able to control docker without the need for <tt>sudo</tt>. |
Latest revision as of 13:54, 26 December 2019
Note - vm and container is used below interchangeably.
Contents
Installation and Verification
# install Docker $ curl -fsSL https://get.docker.com/ | sh # add your-user to docker group to be able to run docker as non-root $ usermod -aG docker your-user # you'll need to log out and in after this, or run all docker commands as root # verify the installation $ docker run hello-world # this should download image from docker hub, and print "Hello from Docker." message
As a rule of thumb: `docker` is the "super-system" used to manage docker containers (and more). `docker-compose` does the same tasks as docker, but only on containers defined in docker-compose.yml file in current directory. So, `docker ps -a` will list all containers, `docker-compose ps` will list info about all containers from local docker-compose.yml file.
If something goes wrong, check
$ docker-compose logs
or
$ docker logs container-id
Stack in Separate Containers
Let's create few containers to hold different parts of the stack:
- nginx
- php-fpm
- mysql
- data volume for mysql
- kyoto tycoon with python
- data volume for kyoto tycoon
First, create config file for docker compose, called docker-compose.yml .
nginx: # based on latest nginx image image: nginx:latest ports: # map vm's port 80 to local port 8080 - 8080:80
Now we have defined our first image, let's get it running:
$ docker-compose up -d # you should be able to reach the nginx on localhost:8080 now; # you can always check running containers, incl. ports map, with $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e795e45c3e6b nginx:latest "nginx -g 'daemon off" 24 hours ago Up 24 hours 443/tcp, 0.0.0.0:8080->80/tcp dockertut_nginx_1 # using container ID or name from `docker ps`, you can get lots of useful info with $ docker inspect {container-id|name}
Adding php-fpm
Let's now add VM for php-fpm, and edit the docker-compose.yml like this:
nginx: build: # don't use image, build based on ./docker/nginx/Dockerfile ./docker/nginx/ ports: # vm's port 80 will be available as 8080 on localhost - 8080:80 links: # has access to 'php' vm - php volumes: # mount current directory as /var/www/html inside the container - .:/var/www/html php: image: php:5.5-fpm expose: # expose port 9000 only to other vm's, not host machine like the 'ports' command - 9000 volumes: - .:/var/www/html
Now the nginx image is based on Dockerfile in ./docker/nginx/ folder, which should look like this:
FROM nginx:latest COPY ./default.conf /etc/nginx/conf.d/default.conf
See official Dockerfile reference for details.
This will build vm from nginx:latest image, and copy ./docker/nginx/default.conf to /etc/nginx/conf.d/ in the vm. Create this file with the following content:
server { listen 80 default_server; root /var/www/html; index index.html index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } access_log off; error_log /var/log/nginx/error.log error; sendfile off; client_max_body_size 100m; location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors off; fastcgi_buffer_size 16k; fastcgi_buffers 4 16k; } location ~ /\.ht { deny all; } }
Note that root /var/www/html; will actually use the mount of our local directory.
Also note fastcgi_pass php:9000; that uses the link created using links: key in the docker-compose.yml.
Now, let's just add index.php in the root folder (where docker-compose.yml resides):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <?php echo "this is php!"; ?> </body> </html>
Let's start the images; this time, php image should be pulled as well:
$ docker-compose up -d Pulling php (php:5.5-fpm)... 5.5-fpm: Pulling from library/php efd26ecc9548: Already exists <-- the nginx image, already pulled a3ed95caeb02: Download complete ...
If you get "Service 'nginx' needs to be built, but --no-build was passed." message, run `docker-compose build` and again `docker-compose up -d`. Verify all is OK and started:
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fd04b796e34f dockertut_nginx "nginx -g 'daemon off" 4 seconds ago Up 4 seconds 443/tcp, 0.0.0.0:8080->80/tcp dockertut_nginx_1 402fb35b762e php:5.5-fpm "php-fpm" 5 seconds ago Up 4 seconds 9000/tcp dockertut_php_1
Note that nginx's image name has changed, since we have built a new one.
Now, when you open localhost:8080, you should get "this is php!" message. Open the index.php file, and edit it; the change should be immediately reflected. Sweet!
Data Volumes
Both the nginx and php vm's now use local folder through the volumes directive.
Better yet is to have a separate container; we'll build this container based on some image we're already using (to avoid having yet another image downloaded), but it won't be running - it'll just sit there, collecting data. Change docker-compose.yml like this:
nginx: build: ./docker/nginx/ ports: - 8080:80 links: - php volumes_from: - app php: image: php:5.5-fpm expose: - 9000 volumes_from: - app app: # it's good practice to "reuse" some image, not to have yet another one pulled image: php:5.5-fpm volumes: - .:/var/www/html # container won't run - it'll execute `true` and sit there, collecting data command: "true"
Let's check all is OK:
$ docker-compose up -d Creating dockertut_app_1... Recreating dockertut_php_1... Recreating dockertut_nginx_1... # list all containers (note that 'app' container is not listed in `ps`, since it's not running): $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af0110364abf dockertut_nginx "nginx -g 'daemon off" 2 minutes ago Up 2 minutes 443/tcp, 0.0.0.0:8080->80/tcp dockertut_nginx_1 94a1c3d317dd php:5.5-fpm "php-fpm" 2 minutes ago Up 2 minutes 9000/tcp dockertut_php_1 861cca283ceb php:5.5-fpm "true" 2 minutes ago Exited (0) 2 minutes ago dockertut_app_1
and check that localhost:8080 is still responding.
Adding MySQL
Update the 'php' section:
php: build: ./docker/php/ expose: - 9000 links: - mysql volumes_from: - app
And add the following:
mysql: image: mysql:latest volumes_from: - mysqldata # set environment variables environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: test MYSQL_USER: test MYSQL_PASSWORD: test mysqldata: image: mysql:latest volumes: # the /var/lib/mysql will be present in container, and "somewhere" on host - /var/lib/mysql command: "true"
And, create ./docker/php/Dockerfile:
FROM php:5.5-fpm RUN docker-php-ext-install pdo_mysql
Now we're all set to `docker-compose build` and `docker-compose up -d`. Let's check what containers we have now:
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e43265be9680 dockertut_nginx "nginx -g 'daemon off" 16 seconds ago Up 14 seconds 443/tcp, 0.0.0.0:8080->80/tcp dockertut_nginx_1 48cd3b544fb1 dockertut_php "php-fpm" 19 seconds ago Up 17 seconds 9000/tcp dockertut_php_1 0e4f40d9ae8b mysql:latest "docker-entrypoint.sh" 21 seconds ago Up 20 seconds 3306/tcp dockertut_mysql_1 963440e29d89 mysql:latest "docker-entrypoint.sh" 22 seconds ago Exited (0) 20 seconds ago dockertut_mysqldata_1 1458644df104 php:5.5-fpm "true" 4 minutes ago Exited (0) 4 minutes ago dockertut_app_1
Now that all is set up, we can check where did docker mount the folder on host, that is seen as /var/lib/mysql in mysqldata instance:
$ docker inspect dockertut_mysqldata_1 ... "Mounts": [ { "Name": "d1352deaff99b25ee68bc53c07150b12b5eb7028b6182f1c97f71f7e21c8ee1d", "Source": "/var/lib/docker/volumes/d1352deaff99b25ee68bc53c07150b12b5eb7028b6182f1c97f71f7e21c8ee1d/_data", "Destination": "/var/lib/mysql", ...
The Source is the folder on host that docker mounted as Destination in VM.
If you want all volumes removed when deleting docker container, use
$ docker rm -v container-id
Otherwise, the volumes will stay on your disk, taking up space.
You can also list all volumes registered by docker:
$ docker volume ls
and use this to remove all "dangling" volumes:
$ docker volume rm $(docker volume ls -qf dangling=true)
Let's check if mysql is up and running, through terminal. You can open interactive terminal in image like this:
$ docker exec -it dockertut_mysql_1 /bin/bash root@0e4f40d9ae8b:/# mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. ... mysql> _
Neat, huh? The -i means to run interactive command, -t to run in terminal.
Manage Docker as non-root User
By creating docker group, and adding users to it, you may select users that can manage docker daemon and processes:
$ sudo groupadd docker $ sudo usermod -aG docker $USER
Afterwards, restart your machine (or, log out and in, and stop and start the docker daemon), and you should be able to control docker without the need for sudo.