Difference between revisions of "Docker"
m (→Shipyard) |
|||
(96 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
{{WIP box}} | {{WIP box}} | ||
Placeholder for anything to do with Docker (https://docker.com) | Placeholder for anything to do with Docker (https://docker.com) | ||
+ | {{Note box| The contrib has been built from the original notes and I use it to permanently run Rocketchat }} | ||
− | + | === Version === | |
+ | {{ #smeversion: smeserver-docker }} | ||
− | + | '''You can discuss all things related to this page on the forums [http://forums.contribs.org/index.php/topic,51181.0.html here]''' | |
− | + | ||
+ | '''There is a separate page that addresses the design of a Docker contrib [http://wiki.contribs.org/Docker_design_concept here]''' | ||
+ | |||
+ | '''There is also a page to discuss on how to create a Docker image of SME [https://wiki.contribs.org/Docker_Image_of_SME here]''' | ||
− | |||
==About== | ==About== | ||
[[File:Docker_logo.png]] | [[File:Docker_logo.png]] | ||
Docker is an open-source project that automates the deployment of applications inside software containers, providing that way an additional layer of abstraction and automatization of operating system–level virtualization on Linux. Docker uses resource isolation features of the Linux kernel such as cgroups and kernel namespaces to allow independent "containers" to run within a single Linux instance, avoiding the overhead of starting virtual machines. | Docker is an open-source project that automates the deployment of applications inside software containers, providing that way an additional layer of abstraction and automatization of operating system–level virtualization on Linux. Docker uses resource isolation features of the Linux kernel such as cgroups and kernel namespaces to allow independent "containers" to run within a single Linux instance, avoiding the overhead of starting virtual machines. | ||
+ | |||
===Why Docker on SME Server?=== | ===Why Docker on SME Server?=== | ||
− | Docker containers hold one or more applications (and all it's | + | Docker containers hold one or more applications (and all it's dependencies) and can be started and stopped at will. The containers, when activated, use the Linux kernel namespaces and are operating isolated from the rest of your server, except for storage/mount points and networking, depending on the configuration of the container. Some applications require special PHP versions or other modifications to your server settings that are not desirable and may effect yum updates and upgrades. Docker containers is a way to have such an application packed with all it's dependencies and run it isolated. You can have multiple containers running, depending on your server hardware capacity. |
Examples: | Examples: | ||
Line 32: | Line 37: | ||
* Security | * Security | ||
* Only use TRUSTED repo's with images. Who build the image, what's in it? | * Only use TRUSTED repo's with images. Who build the image, what's in it? | ||
+ | * Naming convention of images to identify source(person or repo), SME version, application and version. e.g.: | ||
+ | owncloud-7.0.1-smeserver-9.0-john | ||
+ | wordpress-3.9.1-smeserver-8.1-mary | ||
+ | ehour-1.4.1-smeserver-9.0-richard | ||
+ | sharedfolders-2.1.1-smeserver-9.0-fws | ||
+ | frontaccounting-3.2.1-smeserver-8.1-contribsorg | ||
+ | |||
+ | Why the SME Server version in the naming convention if it's all inside the container? Well, it could well be that the application inside the container will use some of SME Server specifics such as the db, templates or perl interaction. In that case we need to make sure that we know for which SME Server the image was build. | ||
+ | |||
+ | |||
+ | * Verification (checksum) of available images | ||
+ | * Setting up trusted docker repo's | ||
+ | * disable docker repo's enabled by default at installation and come up with a command that enables them a la Yum | ||
+ | |||
==Installation== | ==Installation== | ||
− | |||
− | + | ===Contrib=== | |
− | yum install docker- | + | yum --enablerepo=extras install epel-release. |
− | + | yum install smeserver-extrarepositories-docker-ce | |
− | + | signal-event yum-modify | |
− | + | yum --enablerepo=smecontribs,extras,epel install smeserver-docker | |
− | + | signal-event post-upgrade;signal-event reboot | |
− | docker | + | |
− | to | + | (Note the contrib is still in smetest) |
+ | |||
+ | ====Avoiding conflicts==== | ||
+ | |||
+ | docker-compose templates used: | ||
+ | |||
+ | smeserver-docker | ||
+ | 01version | ||
+ | 10HelloWorldTest | ||
+ | |||
+ | smeserver-rocketchat | ||
+ | 20rocketchat | ||
+ | |||
+ | ====config entries==== | ||
+ | |||
+ | config setprop docker iptables false/true - default false | ||
+ | |||
+ | config setprop docker DNS [192,168.10.1,8.8.8.8] - defaults to LocalIP | ||
+ | |||
+ | config setprop docker DockerNetwork [IP range eg 192.168.100.0/24] - defaults to dockers own choice. Range is not yet checked for validity. | ||
+ | |||
+ | There is an action to update the core files: | ||
+ | |||
+ | smeserver-docker-update | ||
+ | |||
+ | {{Note box| Note to self - probably needs quotes around "false" for iptables}} | ||
+ | |||
+ | config show docker | ||
+ | status enabled/disabled - enabled by default | ||
+ | iptables true/false - false by default to prevent docker manipulating iptables | ||
+ | |||
+ | config show containerd | ||
+ | status enabled/disabled - enabled by default - called and used by docker | ||
+ | |||
+ | See if it works: | ||
+ | |||
+ | systemctl status docker | ||
+ | |||
+ | ====Testing==== | ||
+ | |||
+ | We can run docker directly but the preferred method is to use compose | ||
+ | |||
+ | curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose | ||
+ | chmod +x /usr/local/bin/docker-compose | ||
+ | chgrp docker /usr/local/bin/docker-compose | ||
+ | |||
+ | A test compose file is installed. | ||
+ | |||
+ | cd /home/e-smith/files/docker/configs | ||
+ | docker-compose up -d hello_world | ||
+ | |||
+ | Add your own templates to: | ||
+ | |||
+ | /etc/e-smith/templates/home/e-smith/files/docker/configs/docker-compose.yml | ||
+ | |||
+ | or: | ||
+ | |||
+ | /etc/e-smith/templates-custom/home/e-smith/files/docker/configs/docker-compose.yml | ||
+ | |||
+ | To expand the template: | ||
+ | |||
+ | signal-event smeserver-docker-compose-update | ||
+ | cd /home/e-smith/files/docker/configs | ||
+ | docker-compose up -d my_hello | ||
+ | |||
+ | Using plain docker: | ||
+ | |||
+ | docker run hello-world | ||
+ | |||
+ | Other commands: | ||
+ | |||
+ | docker ps -a | ||
+ | docker rm <id> | ||
+ | |||
+ | docker images | ||
+ | docker rmi <id> | ||
+ | |||
+ | ==Things to do== | ||
+ | |||
+ | Plenty | ||
+ | |||
+ | ===Challenges=== | ||
+ | * How to interact with localhost PAM or LDAP from within a container? | ||
+ | |||
+ | I think that you can access localhost services by adding: | ||
+ | |||
+ | --net="host" to docker run | ||
+ | |||
+ | This means any services on the docker container are equally valid 'localhost' services accessible from the server itself so you need to ensure the server is properly firewalled. See Issues below. | ||
+ | |||
+ | * Many more... | ||
+ | |||
+ | |||
+ | ==Notes== | ||
+ | |||
+ | |||
+ | ====Networking==== | ||
+ | |||
+ | {{WIP box | This is still a work in progress. the following are notes for reference only}} | ||
+ | |||
+ | Docker attempts to guess what network to use and sets a bridged interface for it. | ||
+ | Access to the container. | ||
− | + | This allows access to any local services, and any ports in the container will appear locally | |
+ | v1 format | ||
+ | --net="host" | ||
− | + | v2 + format | |
− | |||
− | + | Docker | |
+ | --network host | ||
− | + | Compose | |
− | + | network_mode: host | |
− | |||
− | The | + | This maps container port 80 to host port 8088 |
− | + | ||
+ | # container:host | ||
+ | ports: | ||
+ | - 8080:8080 | ||
+ | |||
+ | So if you ran an Apache container service on port 80, you can connect to it from the host using | ||
+ | |||
+ | container.ip.add:8088 | ||
+ | |||
+ | Using --network host means it is easier to connect to the container using the local IP address. Simple port forwarding/opening will suffice. | ||
+ | |||
+ | However, it exposes all ports on the container locally, and there may also be conflicts with local ports. | ||
+ | |||
+ | Using a port mapping is preferred, but your SME server will then block access container access to local services such as DNS. | ||
+ | |||
+ | The answer is probably to statically set the Docker network, and then add the network to 'Local Network'. You can then expose ports via the docker config entry eg: | ||
− | |||
docker=service | docker=service | ||
− | + | status=enabled | |
− | status=enabled | + | UPDPort=1234 |
+ | TCPPort=8088 | ||
+ | |||
+ | I am working on this currently but the LocalNetworking approach doesn't work. It probably need manipulation of the firewall with templates. | ||
+ | |||
+ | === Login to container=== | ||
+ | |||
+ | If permitted, most containers can be logged into using this: | ||
+ | |||
+ | docker exec -t -i -u root <container_name> /bin/bash | ||
+ | |||
+ | ===SME Server specifics=== | ||
+ | By default Docker will store all images, containers and other data in: | ||
+ | /var/lib/docker | ||
+ | |||
+ | For SME Server this is not ideal for we would like to incorporate all Docker data into the pre-defined backup procedure(s) that come with SME Server. The preferred location for Docker data would be: | ||
+ | '''/home/e-smith/files/docker''' | ||
+ | |||
+ | ===File permissions=== | ||
+ | |||
+ | You may have issues writing to local filesystems from Docker images. | ||
+ | |||
+ | First add something like this to your compose file | ||
+ | |||
+ | volumes: | ||
+ | - /opt/uploads/:/opt/uploads/ | ||
+ | |||
+ | You may need to find out what permissions are required. | ||
+ | |||
+ | |||
+ | In RocketChat I had to add a dummy user and group like this | ||
+ | |||
+ | mkdir -p /opt/uploads | ||
+ | chmod 0777 /opt/uploads | ||
+ | |||
+ | I then could upload and check the ID that docker users. I thins case it was 65533 | ||
+ | |||
+ | So I then did: | ||
+ | groupadd -g 65553 rocketchat | ||
+ | useradd -s /sbin/nologin -u 65533 -d /dev/null -g rocketchat rocketchat | ||
+ | chmod 0744 /opt/uploads | ||
+ | |||
+ | And then test again. | ||
+ | |||
+ | ===Using a Docker image=== | ||
+ | |||
+ | You should generally be prefer to use docker-compose for images. | ||
+ | |||
+ | |||
+ | ==Building your own images== | ||
+ | * Notes | ||
+ | Manual, or.. | ||
+ | https://github.com/docker/fig | ||
+ | |||
+ | |||
+ | ==Related articles of interest== | ||
+ | * [http://jpetazzo.github.io/2014/01/29/docker-device-mapper-resize/ Container storage and (re)size] | ||
+ | |||
+ | ===Setting up a (Private) Docker repository=== | ||
+ | TBA | ||
+ | |||
+ | * https://blog.codecentric.de/en/2014/02/docker-registry-run-private-docker-image-repository/ | ||
+ | |||
+ | |||
+ | |||
+ | ==='Proposal test image:'=== | ||
+ | An application that requires Java, PHP, Apache, MySQL and LDAP. The localhost MySQL and localhost LDAP should be used by the application. The application should be publicly available either on a subdomain or specific port on the FQDN. The application should only be available between 08:00AM until 19:00PM. | ||
+ | All application data should be incorporated by the default SME Sever backup mechanisms, including the image itself. | ||
+ | |||
+ | * Building the image based on centos6 | ||
+ | * Configure networking, bridges and ports | ||
+ | * Start/restart and stop syntax of the application | ||
+ | * Configure cron | ||
+ | |||
+ | ==General old notes== | ||
+ | The following methods and notes are left for reference. | ||
+ | |||
+ | By default, there are pre-built images available from the official [https://registry.hub.docker.com/ Docker Hub]. In our examples we will use the pre-built centos7 image. | ||
+ | |||
+ | To get a list of all available Centos images you can use: | ||
+ | docker search centos | ||
+ | You will be flooded with available images from the Docker hub. This is because everyone can have a free account on Docker hub and create one repository for him/herself. We limit our testing to the official Centos repo. With all the other images, you are on your own and usage is at your own risk. | ||
+ | |||
+ | ===Downloading a docker image=== | ||
+ | To download the centos7 image to your local server, issue the following command as root: | ||
+ | docker pull centos:centos7 | ||
+ | where the syntax is 'centos' as the main repository and 'centos7' the specific version. Would you issue only 'docker pull centos', then all centos versions will be downloaded. So be specific. | ||
+ | |||
+ | Once the image has been downloaded, you can check your local images by issuing: | ||
+ | docker images | ||
+ | |||
+ | The listing included the Image ID and Name. These are important to run additional commands when the container is running. | ||
+ | |||
+ | |||
+ | ===Running a docker container=== | ||
+ | Now that we have downloaded the centos7 image it's time to give it a spin. To start the cento6 container we can issue the following command: | ||
+ | docker run -t -i --net="host" centos:centos7 bash | ||
+ | This will tell docker to run the centos6 container interactively from the local centos repo, use the host network interface and start bash. After a few seconds you will be presented with the bash prompt inside the centos7 container: | ||
+ | bash-4.1# | ||
+ | and to check if we are really inside the centos6 container we can display the release version: | ||
+ | cat /etc/redhat-release | ||
+ | which will result in: | ||
+ | CentOS release 7.8 (Final) | ||
+ | From here you can use the normal commands like yum etc. | ||
+ | |||
+ | To exit the container you give the normal 'exit' command, which will stop the centos6 container and bring you back to the prompt of your local server. | ||
+ | |||
+ | To run a container in the background, you need to issue to docker run command with the -d flag instead of the -i flag | ||
+ | |||
+ | |||
+ | ===Copy docker images=== | ||
+ | Docker images are stored on your local server. If you want to run the image on another machine you first have to take the image out of your local image repository and save the image in a transferable format. For this the ''save'' the image in .tar format. To get a listing of all available images on your local server: | ||
+ | |||
+ | docker images | ||
+ | |||
+ | will result in (example): | ||
+ | |||
+ | [root@sme9 ~]# docker images | ||
+ | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE | ||
+ | sme9 6.5 55db4355a2de 46 minutes ago 854.7 MB | ||
+ | leszekk/centos_minimalcd 6.5 bc56fa8f1204 8 months ago 452.6 MB | ||
+ | |||
+ | To create a copy of our sme9 image and save it as 'copyofsme9 you need to enter the following command: | ||
+ | docker save sme9:6.5 > /tmp/copyofsme9.tar | ||
+ | |||
+ | which will result in a copyofsme9.tar file in your /tmp directory of your local server. You can now copy/move this file to another server or simply archive it for later usage. | ||
+ | |||
+ | To use the copyofsme9.tar file on another server and use it on that server with Docker, we can load it into the repository of the new server: | ||
+ | docker load -i < /downloads/copyofsme9.tar | ||
+ | |||
+ | After Docker has loaded the file, you can check it's availability by executing: docker images and you can use it just like any other image on your new server. You can use the ''save'' and ''load'' commands to clean up your local repository and share copies of your image. | ||
+ | |||
+ | ===Docker networking=== | ||
+ | |||
+ | some thoughts to share on docker networking | ||
+ | |||
+ | * Network port mapping | ||
+ | http://docs.docker.com/userguide/dockerlinks/ | ||
+ | * Network Configuration | ||
+ | http://docs.docker.com/articles/networking/ | ||
+ | |||
+ | '''Note:''' Could we use FWS webapps to create an apache sub domain where the docker web application can be reached and 'masquerade' an unusual http port? e.g. | ||
+ | owncloud.mydomain.com vs mydomain.com:8000 | ||
+ | Using | ||
+ | mydomain.com/owncloud | ||
+ | would require ibay checking | ||
+ | |||
+ | |||
+ | ===Docker Name resolution=== | ||
+ | |||
+ | |||
+ | Other DNS can be added to the unit file or daemon.json - see further below for details. | ||
+ | |||
+ | Or you could add directly from the command line | ||
+ | docker run -i -t -dns 208.67.220.220 -dns 208.67.220.222 sme9_real:6.5 /bin/bash | ||
+ | |||
+ | ===Docker Compose=== | ||
+ | |||
+ | https://github.com/docker/compose/releases/tag/1.29.2 | ||
+ | |||
+ | curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose | ||
+ | chmod +x /usr/local/bin/docker-compose | ||
+ | |||
+ | ===Shipyard web GUI=== | ||
+ | Deprecated | ||
+ | There is a separate page on how to install Shipyard, the Docker web GUI [http://wiki.contribs.org/Shipyard here] | ||
+ | |||
+ | |||
+ | ===Issues=== | ||
+ | |||
+ | This was a v9 issue. Leaving for reference. | ||
+ | |||
+ | You will find that if you use 'host' networking docker will set /sys as Read Only and you will get an error with the raid_check as per this bug | ||
+ | |||
+ | https://bugs.contribs.org/show_bug.cgi?id=10660 | ||
+ | |||
+ | If you don't use host networking, you use the internal IP address set with docker, but this address is unknown as a local network to SME and it will block any queries emanating from the container. I am looking at this with the contrib. | ||
+ | |||
+ | |||
+ | ===Repo setup=== | ||
+ | |||
+ | db yum_repositories set docker-ce-stable repository \ | ||
+ | BaseURL 'https://download.docker.com/linux/centos/7/$basearch/stable' \ | ||
+ | EnableGroups no \ | ||
+ | GPGCheck yes \ | ||
+ | GPGKey https://download.docker.com/linux/centos/gpg \ | ||
+ | Name 'Docker Stable' \ | ||
+ | Visible yes \ | ||
+ | status enabled | ||
+ | |||
+ | signal-event yum-modify | ||
+ | |||
+ | yum --enablerepo=extras,docker-ce-stable install docker-ce docker-ce-cli | ||
+ | |||
+ | or to try with the smeserver-docker contrib - still modifying this | ||
+ | |||
+ | yum --enablerepo=extras,smetest install smeserver-docker | ||
+ | |||
+ | |||
+ | So we get a service in /etc/systemd/system-preset/49-koozali.preset | ||
+ | |||
+ | config set docker service status enabled | ||
+ | config set containerd service status enabled | ||
+ | mkdir -p /home/e-smith/files/docker | ||
+ | mkdir -p /home/e-smith/files/docker/configs | ||
+ | |||
+ | |||
+ | Startup options | ||
+ | |||
+ | The big issue is getting this to work correctly with the firewall. | ||
+ | |||
+ | https://docs.docker.com/compose/compose-file/compose-file-v3 | ||
+ | |||
+ | Host mode where the container has the same IP as the server and the service runs the same as any other host service, and can talk to other local host services easily, but exposes the container more. | ||
+ | |||
+ | Bridge mode where the container is on it's own internal docker network that is bridged to the local machine, but then queries emanating from the container will have the internal docker IP and can be refused by real 'local' services eg AD/MySQL etc. unless the firewall or other services can be adjusted. | ||
+ | |||
+ | |||
+ | https://docs.docker.com/compose/compose-file/compose-file-v3/#network_mode | ||
+ | |||
+ | network_mode: "bridge" | ||
+ | network_mode: "host" | ||
+ | network_mode: "none" | ||
+ | network_mode: "service:[service name]" | ||
+ | network_mode: "container:[container name/id]" | ||
+ | |||
+ | |||
+ | https://docs.docker.com/compose/compose-file/compose-file-v3/#ports | ||
+ | |||
+ | Port mapping is incompatible with network_mode: host | ||
+ | |||
+ | https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file | ||
+ | |||
+ | We can add startup options via /etc/docker/daemon.json | ||
+ | |||
+ | ===Files to modify?=== | ||
+ | |||
+ | For now I have created a hardcoded file with the content from below | ||
+ | |||
+ | mkdir -p /usr/lib/systemd/system/docker.service.d | ||
+ | |||
+ | /usr/lib/systemd/system/docker.service.d/50koozali.conf | ||
+ | |||
+ | If we template then we would use two fragments like this: | ||
+ | |||
+ | /etc/e-smith/templates/usr/lib/systemd/system/docker.service.d/50koozali.conf/40service | ||
+ | |||
+ | [Service] | ||
+ | Type=notify | ||
+ | # the default is not to use systemd for cgroups because the delegate issues still | ||
+ | # exists and systemd currently does not support the cgroup feature set required | ||
+ | # for containers run by docker | ||
+ | # docker home set to /home/e-smith/files/docker | ||
+ | ExecStart= | ||
+ | ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -g /home/e-smith/files/docker/data | ||
+ | ExecReload=/bin/kill -s HUP $MAINPID | ||
+ | TimeoutSec=0 | ||
+ | RestartSec=2 | ||
+ | Restart=always | ||
+ | |||
+ | /etc/e-smith/templates/usr/lib/systemd/system/docker.service.d/50koozali.conf/80install | ||
+ | |||
+ | [Install] | ||
+ | WantedBy=sme-server.target | ||
+ | |||
+ | expand-template /usr/lib/systemd/system/docker.service.d/50koozali.conf | ||
+ | |||
+ | |||
+ | But now we can use /etc/docker/daemon.json | ||
+ | |||
+ | This can be templated. Key point to avoid is a conflict between the docker internal network and out own. | ||
+ | We also want to know what is happening with IPTables rules | ||
+ | |||
+ | eg | ||
+ | |||
+ | { | ||
+ | "bip": "192.168.100.1/24", << Set our own choice of internal network | ||
+ | "data-root": "/home/e-smith/files/docker/data", << set our own data directory | ||
+ | "dns": ["127.0.0.1", "192.168.10.212"] << set our own DNS | ||
+ | } | ||
+ | |||
+ | ===Docker Networking=== | ||
+ | |||
+ | Docker now does it's own thing with IPTables and it is hard to disable - we need to be careful here | ||
+ | |||
+ | https://docs.docker.com/network/iptables/ | ||
+ | |||
+ | How do we check conflicts? | ||
+ | |||
+ | ip addr show docker0 | ||
+ | |||
+ | docker network ls | ||
+ | |||
+ | docker network inspect bridge | ||
+ | |||
+ | https://www.baeldung.com/ops/docker-network-information | ||
+ | |||
+ | docker network inspect -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}' bridge | ||
+ | 172.17.0.0/16 | ||
+ | |||
+ | So one way is to add it to the daemon.json file (see above) | ||
+ | |||
+ | { | ||
+ | "iptables": false | ||
+ | } | ||
+ | |||
+ | And note: | ||
+ | |||
+ | Restart the Docker daemon and voila: your containers will not be exposed to every possible interface but you will need to explicitly manipulate your iptables rules if you want the traffic to pass through, e.g.: this is needed to NAT your containers: | ||
− | |||
− | |||
− | + | -A POSTROUTING -s 172.17.0.0/24 -o eth0 -j MASQUERADE | |
− | + | An alternative which I use on RocketChat is to proxy calls using mod_proxy_tunnel.so | |
− | |||
− | + | /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/20LoadModule98ExtraMod | |
− | |||
− | |||
+ | { | ||
+ | # Load wstunnel if available | ||
+ | if ( -e '/usr/lib64/httpd/modules/mod_proxy_wstunnel.so' || | ||
+ | -e '/usr/lib/httpd/modules/mod_proxy_wstunnel.so') { | ||
+ | $OUT .= "LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so\n"; | ||
+ | } | ||
+ | } | ||
− | + | You can then use some custom httpd templates to create a proxy pass virtual host. | |
− | |||
− | |||
− | |||
− | |||
− | === | + | ===Docker Compose=== |
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | + | https://docs.docker.com/compose/install/ |
− | + | ||
− | + | Check the latest release: | |
+ | |||
+ | https://github.com/docker/compose/releases/ | ||
+ | |||
+ | curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose | ||
+ | chmod 0700 /usr/local/bin/docker-compose | ||
+ | chgrp docker /usr/local/bin/docker-compose | ||
+ | |||
+ | Add template fragments here to make your compose file: | ||
+ | |||
+ | /etc/e-smith/templates/home/e-smith/files/docker/configs/docker-compose.yml | ||
+ | |||
+ | Note that there is now Compose format. | ||
+ | |||
+ | https://github.com/docker/compose#where-to-get-docker-compose | ||
+ | |||
+ | https://github.com/docker/compose-switch | ||
+ | |||
+ | === Old Unit file === | ||
+ | Previous unit file for ref | ||
+ | |||
+ | [Unit] | ||
+ | Description=Docker Application Container Engine | ||
+ | Documentation=https://docs.docker.com | ||
+ | BindsTo=containerd.service | ||
+ | After=network-online.target firewalld.service containerd.service | ||
+ | Wants=network-online.target | ||
+ | Requires=docker.socket | ||
+ | |||
+ | [Service] | ||
+ | Type=notify | ||
+ | # the default is not to use systemd for cgroups because the delegate issues still | ||
+ | # exists and systemd currently does not support the cgroup feature set required | ||
+ | # for containers run by docker | ||
+ | ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -g /home/e-smith/files/docker | ||
+ | ExecReload=/bin/kill -s HUP $MAINPID | ||
+ | TimeoutSec=0 | ||
+ | RestartSec=2 | ||
+ | Restart=always | ||
+ | |||
+ | # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. | ||
+ | # Both the old, and new location are accepted by systemd 229 and up, so using the old location | ||
+ | # to make them work for either version of systemd. | ||
+ | StartLimitBurst=3 | ||
+ | |||
+ | # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. | ||
+ | # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make | ||
+ | # this option work for either version of systemd. | ||
+ | StartLimitInterval=60s | ||
+ | |||
+ | # Having non-zero Limit*s causes performance problems due to accounting overhead | ||
+ | # in the kernel. We recommend using cgroups to do container-local accounting. | ||
+ | LimitNOFILE=infinity | ||
+ | LimitNPROC=infinity | ||
+ | LimitCORE=infinity | ||
+ | |||
+ | # Comment TasksMax if your systemd version does not support it. | ||
+ | # Only systemd 226 and above support this option. | ||
+ | TasksMax=infinity | ||
+ | |||
+ | # set delegate yes so that systemd does not reset the cgroups of docker containers | ||
+ | Delegate=yes | ||
+ | |||
+ | # kill only the docker process, not all processes in the cgroup | ||
+ | KillMode=process | ||
+ | |||
+ | [Install] | ||
+ | WantedBy=multi-user.target | ||
+ | |||
+ | |||
+ | ==Bugs== | ||
+ | |||
+ | Please raise bugs under the SME-Contribs section in {{BugzillaFileBug|product=|component=|title=bugzilla}}and select the smeserver-docker component or use | ||
+ | {{BugzillaFileBug|product=SME%20Contribs|component=smeserver-docker |title=this link}}. | ||
+ | |||
+ | |||
+ | {{#bugzilla:columns=id,product,version,status,summary |sort=id |order=desc |disablecache=1 |component=smeserver-docker |noresultsmessage="No open bugs found."}} | ||
+ | |||
+ | |||
+ | ==Changelog== | ||
+ | |||
+ | Only released version in smecontrib are listed here. | ||
+ | |||
+ | {{ #smechangelog: smeserver-docker }} | ||
+ | |||
+ | |||
+ | |||
+ | [[Category:Containers]] | ||
+ | [[Category:Contrib]] | ||
+ | [[Category:Containers:Docker]] |
Latest revision as of 11:57, 27 July 2023
Placeholder for anything to do with Docker (https://docker.com)
Version
You can discuss all things related to this page on the forums here
There is a separate page that addresses the design of a Docker contrib here
There is also a page to discuss on how to create a Docker image of SME here
About
Docker is an open-source project that automates the deployment of applications inside software containers, providing that way an additional layer of abstraction and automatization of operating system–level virtualization on Linux. Docker uses resource isolation features of the Linux kernel such as cgroups and kernel namespaces to allow independent "containers" to run within a single Linux instance, avoiding the overhead of starting virtual machines.
Why Docker on SME Server?
Docker containers hold one or more applications (and all it's dependencies) and can be started and stopped at will. The containers, when activated, use the Linux kernel namespaces and are operating isolated from the rest of your server, except for storage/mount points and networking, depending on the configuration of the container. Some applications require special PHP versions or other modifications to your server settings that are not desirable and may effect yum updates and upgrades. Docker containers is a way to have such an application packed with all it's dependencies and run it isolated. You can have multiple containers running, depending on your server hardware capacity.
Examples:
- ownCloud running in a container with a higher version of PHP then SME Server provides
- A postgres application running in a container without having to install Postgres on SME Server
- Service on demand, you can start/start (even scripted) a container when you need the service within the container
- Move containers from one SME Server to another (Back-up or production) without installing the application itself
- Time based service e.g. cron jobs. Only have an application running when you need it.
- Keep SME Server's stock stability, security and flexibility, yet run exotic applications
Considerations
- Storage of image library (local/NAS)
- Storage of Docker application data (local/NAS)
- Networking e.g. bridged with host, new bridge with host or port mapping
- Stand alone all-in-on docker or linked containers
- Security
- Only use TRUSTED repo's with images. Who build the image, what's in it?
- Naming convention of images to identify source(person or repo), SME version, application and version. e.g.:
owncloud-7.0.1-smeserver-9.0-john wordpress-3.9.1-smeserver-8.1-mary ehour-1.4.1-smeserver-9.0-richard sharedfolders-2.1.1-smeserver-9.0-fws frontaccounting-3.2.1-smeserver-8.1-contribsorg
Why the SME Server version in the naming convention if it's all inside the container? Well, it could well be that the application inside the container will use some of SME Server specifics such as the db, templates or perl interaction. In that case we need to make sure that we know for which SME Server the image was build.
- Verification (checksum) of available images
- Setting up trusted docker repo's
- disable docker repo's enabled by default at installation and come up with a command that enables them a la Yum
Installation
Contrib
yum --enablerepo=extras install epel-release. yum install smeserver-extrarepositories-docker-ce signal-event yum-modify yum --enablerepo=smecontribs,extras,epel install smeserver-docker signal-event post-upgrade;signal-event reboot
(Note the contrib is still in smetest)
Avoiding conflicts
docker-compose templates used:
smeserver-docker
01version 10HelloWorldTest
smeserver-rocketchat
20rocketchat
config entries
config setprop docker iptables false/true - default false
config setprop docker DNS [192,168.10.1,8.8.8.8] - defaults to LocalIP
config setprop docker DockerNetwork [IP range eg 192.168.100.0/24] - defaults to dockers own choice. Range is not yet checked for validity.
There is an action to update the core files:
smeserver-docker-update
config show docker status enabled/disabled - enabled by default iptables true/false - false by default to prevent docker manipulating iptables
config show containerd status enabled/disabled - enabled by default - called and used by docker
See if it works:
systemctl status docker
Testing
We can run docker directly but the preferred method is to use compose
curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose chgrp docker /usr/local/bin/docker-compose
A test compose file is installed.
cd /home/e-smith/files/docker/configs docker-compose up -d hello_world
Add your own templates to:
/etc/e-smith/templates/home/e-smith/files/docker/configs/docker-compose.yml
or:
/etc/e-smith/templates-custom/home/e-smith/files/docker/configs/docker-compose.yml
To expand the template:
signal-event smeserver-docker-compose-update cd /home/e-smith/files/docker/configs docker-compose up -d my_hello
Using plain docker:
docker run hello-world
Other commands:
docker ps -a docker rm <id>
docker images docker rmi <id>
Things to do
Plenty
Challenges
- How to interact with localhost PAM or LDAP from within a container?
I think that you can access localhost services by adding:
--net="host" to docker run
This means any services on the docker container are equally valid 'localhost' services accessible from the server itself so you need to ensure the server is properly firewalled. See Issues below.
- Many more...
Notes
Networking
Docker attempts to guess what network to use and sets a bridged interface for it.
Access to the container.
This allows access to any local services, and any ports in the container will appear locally
v1 format --net="host"
v2 + format
Docker
--network host
Compose
network_mode: host
This maps container port 80 to host port 8088
# container:host ports: - 8080:8080
So if you ran an Apache container service on port 80, you can connect to it from the host using
container.ip.add:8088
Using --network host means it is easier to connect to the container using the local IP address. Simple port forwarding/opening will suffice.
However, it exposes all ports on the container locally, and there may also be conflicts with local ports.
Using a port mapping is preferred, but your SME server will then block access container access to local services such as DNS.
The answer is probably to statically set the Docker network, and then add the network to 'Local Network'. You can then expose ports via the docker config entry eg:
docker=service status=enabled UPDPort=1234 TCPPort=8088
I am working on this currently but the LocalNetworking approach doesn't work. It probably need manipulation of the firewall with templates.
Login to container
If permitted, most containers can be logged into using this:
docker exec -t -i -u root <container_name> /bin/bash
SME Server specifics
By default Docker will store all images, containers and other data in:
/var/lib/docker
For SME Server this is not ideal for we would like to incorporate all Docker data into the pre-defined backup procedure(s) that come with SME Server. The preferred location for Docker data would be:
/home/e-smith/files/docker
File permissions
You may have issues writing to local filesystems from Docker images.
First add something like this to your compose file
volumes: - /opt/uploads/:/opt/uploads/
You may need to find out what permissions are required.
In RocketChat I had to add a dummy user and group like this
mkdir -p /opt/uploads chmod 0777 /opt/uploads
I then could upload and check the ID that docker users. I thins case it was 65533
So I then did:
groupadd -g 65553 rocketchat useradd -s /sbin/nologin -u 65533 -d /dev/null -g rocketchat rocketchat chmod 0744 /opt/uploads
And then test again.
Using a Docker image
You should generally be prefer to use docker-compose for images.
Building your own images
- Notes
Manual, or.. https://github.com/docker/fig
Related articles of interest
Setting up a (Private) Docker repository
TBA
'Proposal test image:'
An application that requires Java, PHP, Apache, MySQL and LDAP. The localhost MySQL and localhost LDAP should be used by the application. The application should be publicly available either on a subdomain or specific port on the FQDN. The application should only be available between 08:00AM until 19:00PM. All application data should be incorporated by the default SME Sever backup mechanisms, including the image itself.
- Building the image based on centos6
- Configure networking, bridges and ports
- Start/restart and stop syntax of the application
- Configure cron
General old notes
The following methods and notes are left for reference.
By default, there are pre-built images available from the official Docker Hub. In our examples we will use the pre-built centos7 image.
To get a list of all available Centos images you can use:
docker search centos
You will be flooded with available images from the Docker hub. This is because everyone can have a free account on Docker hub and create one repository for him/herself. We limit our testing to the official Centos repo. With all the other images, you are on your own and usage is at your own risk.
Downloading a docker image
To download the centos7 image to your local server, issue the following command as root:
docker pull centos:centos7
where the syntax is 'centos' as the main repository and 'centos7' the specific version. Would you issue only 'docker pull centos', then all centos versions will be downloaded. So be specific.
Once the image has been downloaded, you can check your local images by issuing:
docker images
The listing included the Image ID and Name. These are important to run additional commands when the container is running.
Running a docker container
Now that we have downloaded the centos7 image it's time to give it a spin. To start the cento6 container we can issue the following command:
docker run -t -i --net="host" centos:centos7 bash
This will tell docker to run the centos6 container interactively from the local centos repo, use the host network interface and start bash. After a few seconds you will be presented with the bash prompt inside the centos7 container:
bash-4.1#
and to check if we are really inside the centos6 container we can display the release version:
cat /etc/redhat-release
which will result in:
CentOS release 7.8 (Final)
From here you can use the normal commands like yum etc.
To exit the container you give the normal 'exit' command, which will stop the centos6 container and bring you back to the prompt of your local server.
To run a container in the background, you need to issue to docker run command with the -d flag instead of the -i flag
Copy docker images
Docker images are stored on your local server. If you want to run the image on another machine you first have to take the image out of your local image repository and save the image in a transferable format. For this the save the image in .tar format. To get a listing of all available images on your local server:
docker images
will result in (example):
[root@sme9 ~]# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE sme9 6.5 55db4355a2de 46 minutes ago 854.7 MB leszekk/centos_minimalcd 6.5 bc56fa8f1204 8 months ago 452.6 MB
To create a copy of our sme9 image and save it as 'copyofsme9 you need to enter the following command:
docker save sme9:6.5 > /tmp/copyofsme9.tar
which will result in a copyofsme9.tar file in your /tmp directory of your local server. You can now copy/move this file to another server or simply archive it for later usage.
To use the copyofsme9.tar file on another server and use it on that server with Docker, we can load it into the repository of the new server:
docker load -i < /downloads/copyofsme9.tar
After Docker has loaded the file, you can check it's availability by executing: docker images and you can use it just like any other image on your new server. You can use the save and load commands to clean up your local repository and share copies of your image.
Docker networking
some thoughts to share on docker networking
- Network port mapping
http://docs.docker.com/userguide/dockerlinks/
- Network Configuration
http://docs.docker.com/articles/networking/
Note: Could we use FWS webapps to create an apache sub domain where the docker web application can be reached and 'masquerade' an unusual http port? e.g.
owncloud.mydomain.com vs mydomain.com:8000
Using
mydomain.com/owncloud
would require ibay checking
Docker Name resolution
Other DNS can be added to the unit file or daemon.json - see further below for details.
Or you could add directly from the command line
docker run -i -t -dns 208.67.220.220 -dns 208.67.220.222 sme9_real:6.5 /bin/bash
Docker Compose
https://github.com/docker/compose/releases/tag/1.29.2
curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose
Shipyard web GUI
Deprecated There is a separate page on how to install Shipyard, the Docker web GUI here
Issues
This was a v9 issue. Leaving for reference.
You will find that if you use 'host' networking docker will set /sys as Read Only and you will get an error with the raid_check as per this bug
https://bugs.contribs.org/show_bug.cgi?id=10660
If you don't use host networking, you use the internal IP address set with docker, but this address is unknown as a local network to SME and it will block any queries emanating from the container. I am looking at this with the contrib.
Repo setup
db yum_repositories set docker-ce-stable repository \ BaseURL 'https://download.docker.com/linux/centos/7/$basearch/stable' \ EnableGroups no \ GPGCheck yes \ GPGKey https://download.docker.com/linux/centos/gpg \ Name 'Docker Stable' \ Visible yes \ status enabled
signal-event yum-modify
yum --enablerepo=extras,docker-ce-stable install docker-ce docker-ce-cli
or to try with the smeserver-docker contrib - still modifying this
yum --enablerepo=extras,smetest install smeserver-docker
So we get a service in /etc/systemd/system-preset/49-koozali.preset
config set docker service status enabled config set containerd service status enabled mkdir -p /home/e-smith/files/docker mkdir -p /home/e-smith/files/docker/configs
Startup options
The big issue is getting this to work correctly with the firewall.
https://docs.docker.com/compose/compose-file/compose-file-v3
Host mode where the container has the same IP as the server and the service runs the same as any other host service, and can talk to other local host services easily, but exposes the container more.
Bridge mode where the container is on it's own internal docker network that is bridged to the local machine, but then queries emanating from the container will have the internal docker IP and can be refused by real 'local' services eg AD/MySQL etc. unless the firewall or other services can be adjusted.
https://docs.docker.com/compose/compose-file/compose-file-v3/#network_mode
network_mode: "bridge" network_mode: "host" network_mode: "none" network_mode: "service:[service name]" network_mode: "container:[container name/id]"
https://docs.docker.com/compose/compose-file/compose-file-v3/#ports
Port mapping is incompatible with network_mode: host
https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file
We can add startup options via /etc/docker/daemon.json
Files to modify?
For now I have created a hardcoded file with the content from below
mkdir -p /usr/lib/systemd/system/docker.service.d
/usr/lib/systemd/system/docker.service.d/50koozali.conf
If we template then we would use two fragments like this:
/etc/e-smith/templates/usr/lib/systemd/system/docker.service.d/50koozali.conf/40service
[Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker # docker home set to /home/e-smith/files/docker ExecStart= ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -g /home/e-smith/files/docker/data ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always
/etc/e-smith/templates/usr/lib/systemd/system/docker.service.d/50koozali.conf/80install
[Install] WantedBy=sme-server.target
expand-template /usr/lib/systemd/system/docker.service.d/50koozali.conf
But now we can use /etc/docker/daemon.json
This can be templated. Key point to avoid is a conflict between the docker internal network and out own. We also want to know what is happening with IPTables rules
eg
{ "bip": "192.168.100.1/24", << Set our own choice of internal network "data-root": "/home/e-smith/files/docker/data", << set our own data directory "dns": ["127.0.0.1", "192.168.10.212"] << set our own DNS }
Docker Networking
Docker now does it's own thing with IPTables and it is hard to disable - we need to be careful here
https://docs.docker.com/network/iptables/
How do we check conflicts?
ip addr show docker0
docker network ls
docker network inspect bridge
https://www.baeldung.com/ops/docker-network-information
docker network inspect -f 'Template:Range .IPAM.ConfigTemplate:.SubnetTemplate:End' bridge 172.17.0.0/16
So one way is to add it to the daemon.json file (see above)
{ "iptables": false }
And note:
Restart the Docker daemon and voila: your containers will not be exposed to every possible interface but you will need to explicitly manipulate your iptables rules if you want the traffic to pass through, e.g.: this is needed to NAT your containers:
-A POSTROUTING -s 172.17.0.0/24 -o eth0 -j MASQUERADE
An alternative which I use on RocketChat is to proxy calls using mod_proxy_tunnel.so
/etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/20LoadModule98ExtraMod
{ # Load wstunnel if available if ( -e '/usr/lib64/httpd/modules/mod_proxy_wstunnel.so' || -e '/usr/lib/httpd/modules/mod_proxy_wstunnel.so') { $OUT .= "LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so\n"; } }
You can then use some custom httpd templates to create a proxy pass virtual host.
Docker Compose
https://docs.docker.com/compose/install/
Check the latest release:
https://github.com/docker/compose/releases/
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod 0700 /usr/local/bin/docker-compose chgrp docker /usr/local/bin/docker-compose
Add template fragments here to make your compose file:
/etc/e-smith/templates/home/e-smith/files/docker/configs/docker-compose.yml
Note that there is now Compose format.
https://github.com/docker/compose#where-to-get-docker-compose
https://github.com/docker/compose-switch
Old Unit file
Previous unit file for ref
[Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com BindsTo=containerd.service After=network-online.target firewalld.service containerd.service Wants=network-online.target Requires=docker.socket [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -g /home/e-smith/files/docker ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. # Both the old, and new location are accepted by systemd 229 and up, so using the old location # to make them work for either version of systemd. StartLimitBurst=3 # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make # this option work for either version of systemd. StartLimitInterval=60s # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity # Comment TasksMax if your systemd version does not support it. # Only systemd 226 and above support this option. TasksMax=infinity # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process [Install] WantedBy=multi-user.target
Bugs
Please raise bugs under the SME-Contribs section in bugzilla and select the smeserver-docker component or use
ID | Product | Version | Status | Summary |
---|---|---|---|---|
11892 | SME Contribs | 10.0 | CONFIRMED | First import smeserver-docker to SME 10 [smeserver-docker] v0.4-1 |
Changelog
Only released version in smecontrib are listed here.