What are we doing here?

This blog includes a series of videos and references to help new users or enthusiasts better understand how to use open source and free technology tools. The quick links includes more information for accessing many of the tools covered along with other references to learn more for taking advantage of these tools.

Click HERE to see the full list of topics covered!
Showing posts with label docker. Show all posts
Showing posts with label docker. Show all posts

Connecting new Docker Containers to an Existing Docker Compose

Docker is amazing, but it has it's own way of handling things. 

Docker-Compose is amazing and it to needs to be used the right way. 

This post is about explaining how to attach new containers to existing containers already set up via docker-compose. 

Background:

Docker-Compose, when it brings up a bunch of containers or 'services' puts all of them in the same network with a common subnet and DNS so each service can talk to one-another based on the service name. 

Example:

mongodb://root:mongopwd@mongo:27017/

The 'mongo' in that line is the service name, and to connect say Mongo-Express to that container we can simply call the service name. Without the DNS component of the networking layer, we would need to know the specific IP of the container to connect. The 27017 is the port which is the default for MongoDB. 

Normally with Docker-Compose all the services or containers that run within the config file - normally docker-comopose.yml - will be given their own subnet and DNS to operate so they can just talk to one-another based on the service name. 

Example:

version: '3.1'

services:

  mongo:
    image: mongo
    container_name: mongodb
    restart: unless-stopped
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: mongopwd

  websvr:
    build: ./work
    container_name: web4mongo
    restart: unless-stopped
    volumes:
      - ./work/src:/var/www/html
    ports:
      - 80:80
    links:
      - mongo
    depends_on:
      - mongo

The services are denoted using indentation, and shown as 'mongo' and 'websvr'. Those two can than talk to one-another using 'mongo' or 'websvr' rather than the IP address of each individual container. This is really powerful since it makes the networking portion more easily understood, and also more easily repeatable since containers brought up on one system may get assigned different IP ranges than say on a different system. From a code perspective, just call the service name each time and all of that is handled. 

Adding another container:

However say we want to add a container. Often you need to adjust the docker-compose config, stop / remove the containers, and restart them. If the containers are removed and don't have a mapped volume to store the data already created, than the data could be lost. 

Less than ideal. 

However, with Docker you can map new containers to the network!

First find the network. Run 'docker network list'

 NETWORK ID     NAME                                DRIVER    SCOPE
50711*******   bridge                                bridge    local
ca9cc
*******   host                                  host      local
118ef
*******   lamp_default                          bridge    local
1887b
*******   local-debug_default                   bridge    local
9299d
*******   none                                  null      local
06023
*******   ournoteorganizer_default              bridge    local
186fc
*******   phps3object_default                   bridge    local
2209e
*******   wordpress_default                     bridge    local

An output like the above may be what you see depending on the number of Docker instances you are running or have setup. This gives us the network names which we can use to attach a new container in the network. 

For this example we are adding a Mongo Express which is a web-based graphical UI that helps see and interact with a MongoDB database more easily. It's not necessary and should be disabled (docker stop mongo-express) when not used, but it is clearer, and possibly faster than running through all the mongosh commands.

Here is what we run:

sudo docker run --name=mongoex -p=8082:8081 \
--network=ournoteorganizer_default \
-e ME_CONFIG_MONGODB_ADMINUSERNAME=root \
-e ME_CONFIG_MONGODB_ADMINPASSWORD=mongopwd \
-e ME_CONFIG_MONGODB_URL=mongodb://root:mongopwd@mongo:27017/\
mongo-express

We create the new container using the run command, give it a name, define the port mapping between the host and the container, then assign it to the same network as the the original Docker-Compose group of containers - placing it in the same subnet and DNS / user space. Then we assign the necessary environment varilables to match the existing ones shown in the previous docker-compose.yml file. Finally specific the Docker image as mongo-express. 

This worked a treat for me since I had commented out Mongo Express in my pusblished OurNoteOrganizer application due to security concerns. Now I have a Mongo Express container I can call up when I need it or turn it off when I don't. 

Start: sudo docker start mongoex

Stop: sudo docker stop mongoex

Docker Compose is amazingly powerful, but understanding how it works is important to take full advantage of it. Knowing that it is essentially an automated networking stack + container creation makes it possible to work with without having to destroy containers and possibly lose information.

Upgrading Nextcloud in Docker

 

This is a quick post on updating and maintaining a Docker install of Nextcloud. I have had my install pretty much untouched since I first put it up about a year or two ago. The whole time it's been fine, but I heard about performance improvements in later versions and have begun the process of upgrading the service. 

Here are some steps to check for. 

Based on my previous restore experience, I know that going from one version of docker to the next can sometimes be version dependent. What has worked in managing the upgrades is to upgrade one version at a time. 

To do this, first check what Nextcloud describes as the newest version. Enter the system as the 'admin' user, go to 'Settings' -> 'Overview'. A screen like below should show.


Nextcloud will give a few suggestions of areas to make your instance more secure or highlight any issues (this is a private instance without HTTPS, as noted, and without a lot of the Calendar and other apps), and it will display what the next version is. 

That next version will be the upgrade target for the Docker instance.

In your host, you can first pull the new Docker image of Nextcloud by running:

sudo docker image pull nextcloud:<the target version from the UI>

This will save some time in the upgrade.

Next make sure everything is saved and no one is using the containers. Stop the containers with:

sudo docker stop <nextcloud container name> <nextcloud DB container name>

In my sample docker-compose reference the command would look like:

sudo docker stop nxtcloud nxtclouddb

Then modify the docker-compose.yml file with the new image specified just downloaded. For example 25.0.3 shown below. 

app:
  image: nextcloud:25.0.3
  container_name: nxtcloud
  restart: unless-stopped

  ports

  .....

Once changed bring up the containers again.

sudo docker-compose up

Here I omit the -d for running in the background. This offers a terminal view of the upgrade similar to below.


Give that a few minutes, and then the Nextcloud should be upgraded to the new version. 

To ensure the containers can be run in the background without an active terminal, stop the containers again, and re-run the sudo docker-compose up -d with the -d flag.

Some more information about Nextcloud is throughout the blog - just click on the Overview page or search by the Nextcloud tags on the right-hand side. 

For more information about the reference docker-compose to get started with it and a MariaDB instance check out the source in GitHub.

Backing up MongoDB

Explored in previous posts and videos, MongoDB is a great way to store information without a schema. All of the information is stored in a JSON like format called BSON which essentially are documents, but similar to a SQL Database the data cannot be directly read on the host system. 

I was interested in learning some more about how to backup the files. Turns out that MongoDB provides a dump tool similar to MySQL called mongodump and mongorestore

To get started one can run the following command on their host system or container. If you used the MongoDB Docker image, the mongodump command can be run inside the container directly. 

Local Run

mongodump -u=<user> -p=<password> --authenticationDatabase=admin --db=<database to download>

The part '--authenticationDatabase' is important. On the MongoDB container the users allowed to access the database are specified are in that 'admin' database on the Mongo instance, and it must be defined in the mongodump command for the connection to be successful.

Similar to mysqldump, the mongodump command can also be used from a remote host.

Install the MongoDB Command Line Database Tools on the remote host. They offer the tools for Windows, Linux, and MacOS. 

*Note on Fedora 36, using the RedHat/CentOS 8.0 package worked. *

Modify the previous command to the below:

Remote Run

mongodump --host=<Domain/IP> --port=<Mongo service port - default is 27017> -u=<user> -p=<password> --authenticationDatabase=admin --db=<database to download>

Assuming a connection can be made all of the database files and relevant metadata will come down to the directory where the command was run. A successful run will look similar to the below. 

Once complete you will see a directory called 'dump' with the database(s) listed as directories inside. 

To specify the output location on the local system (the system being used to access and backup the MongoDB instance) you may use the '-o' or '--output' flag. 

Remote Run | Specify Download Location

mongodump --host=<Domain/IP> --port=<Mongo service port> -u=<user> -p=<password> --authenticationDatabase=admin --db=<database to download> -o=<directory location>

Restoring data from a Mongodump

The companion utility to mongodump is mongorestore. Mongorestore works similarly to mongodump, but the user specifies the db and the back up files. 

mongorestore --host <Domian/IP:Port> --authenticationDatabase=admin -u <user> -p <password> -d <db to restore> <backup folder location>

One additional tip: 

If the container was installed using the same docker-compose from the PHP and MongoDB tutorial, the port for the MongoDB Instance isn't exposed on the local system. This is good from a security standpoint. The companion web server accesses using the hostname from the private Podman / Docker network. To access the container host from the physical machine you need to use the IP address of the MongoDB container itself.

Using either Docker or Podman, run the inspect command to check to find the Network information. 

sudo podman inspect <container name or ID> | grep "IPAddress" OR
sudo docker inspect <container name or ID> | grep "IPAddress"

Additional information:

Information about using mongodump

Information about using mongorestore

Firewalld and Podman - Protecting Your DB

 

The above output is an interesting discovery I found with the relationship between Podman and Firewalld (aka firewall-cmd). 

So I was tinkering with a semi-production environment that is a web server with Apache and PHP on it, and a MySQL database running as a container. This was originally just done quickly, but is becoming more and more important. Honestly, long term, I may want to just move the database to an actual VM that has all the bells and whistles - like Cron for scheduled backups, etc. I digress.

The point is I was reading an article that a lot of sites have MySQL databases without SSL. If you run your database in a container, there is a good chance it also doesn't have SSL since most Docker images do not include that out-of-the-box. I personally don't think it is a problem if the service is on a truly internal network, but I ran a Telnet check from a remote system and it responded. Holy ^$%%@#$!

Now the port shouldn't be exposed, the firewall-cmd rules for the external interface don't allow that port type. However, with further testing I was able to connect a phpmyadmin to that host from a completely remote system. Holy#$%^&*&^%$!

What happens is on RedHat / CentOS / Fedora, podman essentially knows about firewall-cmd and spins itself into the zone trusted. You get that source and everything is available from that source. This also allows the outside world to come to that port - which is NOT what we want.

Turns out though, that it is relatively straightforward to lock this down.

Backup all the databases using a mysqldump - or in this case just by using a PHPMyAdmin to export. 

Then destroy the current container. Run the following:

podman stop <DB container name>

podman rm <DB container name>

Assuming the container has its /var/lib/mysql directory mounted to the host using the -v or --volume at creation likely the backups won't need to be restored. Just re-run the container creation command (example below).

podman run -d --name mySQLdb -v <host directory>:/var/lib/mysql -p 127.0.0.1:3306:3306 --restart=unless-stopped -e MYSQL_ROOT_PASSWORD=<password> -e lower_case_table_names=1 mysql:5.7

The difference in the above command is that the localhost IP - 127.0.0.1 - is specified along with the port value. As such, the container is now only reachable by services or other containers running on the local system. 

Now testing with a telnet command to that host with port 3306 shows unreachable, but the local web server can still interact with the database. 

telnet: Unable to connect to remote host: No route to host

Most tutorials and explanations about Docker or Podman or containers in general usually cover the "-p" call as a network port. However, it can also be used to bind a specific IP:portnum which is very important to helping protect a system that is running on the Internet. 

I hope this can help others keep themselves safer when using containers in production.

Intro to Minio S3 Object Storage

 


Minio  S3 object storage is powerful and easily run in a Docker, LXD, Podman or other container environment. Super easy to setup, super easy to understand, and the latest console has a ton of features to improve the intuitiveness of the platform. 

The command run in the video is the same as in the previous blog:

sudo docker run -it --name=miniotest -p 9000:9000 -p 9001:9001 minio/minio server /data --console-address ":9001"

To map a volume to the container one can create a directory on the local machine and add the -v <localvolume>:/data to the above command. That should help keep the buckets and related files available if the container is ever removed.

Example below from the container created in this test.



More information is below:

Happy to field any questions, just let me know. 



Creating a web application with a MongoDB backend and Docker


This is a bit of a POC that turned into a project.

I was playing with MongoDB to create a front-end that would store data in a user friendly way. I didn't want to take on things like WordPress or others, and had an idea for a note taking application that could be on-prem, and put teams or catalogs first with grouping.

I think there is quite a bit more that could be done, like adding reminders/due dates to the posts/notes and adding more management to groups so new authors can add more people to a project/group. For now this is being used to demonstrate the capabilities of PHP with MongoDB.

A killer feature in MongoDB is the ability for it to not need to be primed in anyway. This feature allows for this app install using Docker to exist. In a traditional/relational database a user needs to setup the database and table structure in order for data to be inserted. With NoSQL/MongoDB you can just point an app at the DB and with the correct credentials start adding and editing a whole DB in the service itself. This is what I do in the initial login screen. I check if the DB and admin exist, and if not, they get automatically populated so a user on a completely fresh install can just start using the application. 

Currently this application is far from perfect, but I hope it helps users get an idea of what an be done using PHP, HTML, CSS, and MongoDB together. I also hope it can be useful, and if anyone requires additional assistance, please feel free to leave comments on the GitHub page. I am not at the caliber of a professional open source developer, and have limited time, but I am interested in the feedback, and willing to assist as I can to further promote usage of the project.

I hope this can be a useful project either for internal team collaboration or simply as reference code for other users. The code is published with the permissible Apache 2.0 license (same as Apache and MongoDB that it builds off).

Notes:

Source code is here: https://github.com/JoeMrCoffee/OurNoteOrganizer

A word on TinyMCE

TinyMCE is an external text editor which is used to help enhance the ease for writing and editing posts. It is an external tool that requires connectivity to external networks in order to function. For environments that do not have external Internet connectivity a standard 'textarea' without rich formatting is employed.

As this project is made to be hosted on any on-prem environment, there is no TinyMCE API key provided or registered. Users can create their own keys based on their domains and needs. To remove the notification about getting started, users can follow the quick steps, create their own API key, and add it to line 8 of the newpost.php file.

More information on TinyMCE and getting started:

https://www.tiny.cloud/

https://www.tiny.cloud/docs/quick-start/


Getting started with PHP and MongoDB

 

This post and video delve into the world of schemaless, NoSQL databases. NoSQL databases are powerful and interesting ways of storing data at scale. Because they do not have a traditional table that dictates what kind of data needs to be written, NoSQL databases, like MongoDB, can accept data much more easily. There is also the benefit that, at scale, a cluster of multiple nodes can be hosting a common database and collection where as a traditional database cannot scale-out horizontally. 

In cloud computing, NoSQL databases are what drive the likes of Amazon, Google, Facebook and more. 

In order to learn more about them I wanted to try and replicate what I know on PHP and MySQL (a schema or relational database), and apply it to PHP with MongoDB. I did struggle a bit because of the way I was building the container and my lack of familiarity with the way Composer works. As such I thought I'd share my progress and provide the docker-compose file along with a run through of how to get it setup and running. 

The Dockerfile and Docker Compose script are located on my GitHub with no license and anyone can feel free to use the repository to quickly bring up and test a LAMP stack using MongoDB instead of MySQL or MariaDB. Just git clone, and run docker-compose up from the directory and it should build everything. 

Also included in the repo is a very simple HTML form that will write a Name and Age to the MongoDB instance. These two web pages are essentially just offered as a reference for how to connect and get started. 

Docker Compose source: https://github.com/JoeMrCoffee/MongoLAMP

Additional references that I found helpful:

Official documentation on using PHP with MongoDB:
https://docs.mongodb.com/drivers/php/

Official Docker image for MongoDB and Mongo-Express:
https://hub.docker.com/_/mongo
(This was the base for the docker compose minus the Apache PHP image)

Another great tutorial which is worth a look as well.
https://www.javatpoint.com/php-mongodb

Recover a broken NextCloud

This is not intended to be a definitive guide. I am just sharing my experience after crashing my NextCloud container. 

I performed an upgrade on my "NAS" (Ubuntu server on an old laptop) by adding a second, larger external USB drive. This is not best practice, but works for me as a file backup. 

In adding the drive, I was trying to be careful, but obviously I wasn't careful enough. I changed the fstab file (this is where Linux knows what drives and filesystems to mount), to include the new drive. That generally worked fine, but I was mounting using the /dev/sda~/dev/sdb terminology for the drives. When Linux boots it checks the storage driver for what hardware and assigns it to the /dev/ based on its type (nvme will show up /dev/nvme####, SATA drives will usually show up as /dev/sdX#). What happened was because Linux assigns the /dev type at boot, when I rebooted with the new external drive the /dev assignments changed. SURPRISE!!! That then meant 2 out of 3 of my fstab assignments are wrong. They tried to mount backwards.

So that wasn't good. My root drive was using the UUID, which is better and should be used. For the other 2 external drives I changed to using the drive label that can be set when initially formatting the drives. Something like the below:

LABEL=usbbackup /media ntfs defaults 0 0

This was fine for getting everything straightened out. However, in the process of the drives mounting in the wrong order, my NextCloud and MariaDB containers got out of whack. I couldn't log in and just had an "Internal server error" message. 

The help pages mentioned that one can use maintenance mode and using the occ tools to help fix something similar. Unfortunately, the Docker install doesn't have a lot of tools, like 'sudo' to help test. Fortunately, all the data for both containers was 100% still intact as it was mounted using the volume parameter from the docker-compose file. This means, in theory, you can just nuke the containers, rebuild new containers with the same volume points, and get back in business. 

At this point, I want to stop and say that while this is possible and worked for me, be very very very careful that the data is still intact for both the database and NextCloud instances. If anything beyond the defaults in the docker-compose file was changed - i.e. additional packages or other things were added in the container - the next steps will wipe all of that. 

Steps I used:

Stop the containers:

  sudo docker stop nxtcloud nxtclouddb 

Note: Container names are defined as such in my version of the docker-compose file. Running sudo docker ps -a will show the current names of all the containers.

Backup the container data directories to somewhere safe. Leave the data intact in the original location. 

Note: If you can't get the containers restarted and need to truly nuke and pave, all the files in NextCloud are stored under the NextCloud data directory. On the container this would be /var/www/html/data/, on the local volume it would be under the <NextCloud install directory>/data/data/ on the host system using my docker-compose file.

Delete the containers:
  sudo docker rm nxtcloud nxtclouddb

Download the latest version of the NextCloud image:
 sudo docker image pull nextcloud:latest

Update the docker-compose file to specify the MariaDB version as 10.5:
 image: mariadb:10.5

This step is run because on my first go, NextCloud had issues with the latest version of MariaDB (version 10.6 I believe). The docker-compose pulled the latest image version by default.

Recreate and run the containers. From the directory of the docker-compose and data directories run:
 sudo docker-compose up -d

Once the container names appear, verify they are running correctly:
 sudo docker ps

Now open to the NextCloud browser page. In my case it asked to update the NextCloud instance. This triggered everything to get sorted out in NextCloud, and I could log in and everything was fine. Users can log in, data was intact, and things were copacetic.

The updated version of my NextCloud docker-compose file to reflect the change to use MariaDB version 10.5 is HERE.

Moral of the story, always stop running services on a server, especially the Docker containers BEFORE making a hardware update to the system. No matter how simple it may seem, put the host system in maintenance mode first.

More information on /etc/fstab configs is available here:
  https://linuxhint.com/write-edit-etc-fstab/
  https://help.ubuntu.com/community/Fstab

Hopefully this helps demonstrate how volumes can be used to keep container data persistent, along with the flexibility of working with containers. I was lucky that the upgrade was able to trigger a re-sync of the NextCloud instance and the database. Some more information about doing this manually is in the NextCloud Doc page.
  https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html



Nextcloud in Docker!




So this is something I've been debating for a while - stick with a pure SMB share or try setting up Nextcloud.

Nextcloud is essentially local, open source, on-prem Dropbox with an ever growing feature set. It trumps SMB (a local Windows or Linux SAMBA file share) in many regards with things like apps for iOS / Android, calendar sync, email sync, and more. 

It's far more complicated than SMB or a generic NAS share in many respects, but that honestly makes it more easy to use for the end user - simply go to the local site or IP on the LAN, enter credentials and begin using it. 

I set this up using Docker and I wanted to share the experience. 

Using the official Docker Hub information was fine - essentially being able to test something easy in a single command.

$ docker run -d -p 8080:80 nextcloud

After running that in docker (likely will need sudo to grant permissions when running in Linux) you can just log in using your browser <server / computer IP>:8080.

That works, but isn't ideal. Nextcloud will tell you to change the database from their default sqlite to another - better, or more comprehensive - database immediately. 

For better use there is the docker-compose suggestion on the Docker hub Nextcloud page. I followed and tweaked that. It works really well, but there are some things to watch for. 

Modified docker-compose

    *Update* This is also now on GitHub: NextCloudDockerCompose

My version of the docker-compose file changes the following: 

  • Update the version of docker compose to 3, 
  • Adjust the way persistent volumes are defined to a local file folder vs the generic persistent file folder in the reference, 
  • Changed the restart preference to 'unless-stopped' in case you do need to stop the container it won't keep restarting (it should restart on a device/VM reboot) 
  • Add names to both the MariaDB and Nextcloud containers. That last bit makes it a bit easier to manage when you want to restart or interact the container.
Save the file in a folder as docker-compose.yml, adjust the passwords and directories/folders to your needs then run docker-compose up -d and it should run.

When I initially started this it worked well, but on first login I ran into an issue due to the way MariaDB was handling the input from Nextcloud. This might be my luck or just the age of the Nextcloud docker container post. I found this workaround which solved the issue:

Wayne's garden - essentially running the below command in the MariaDB (MySQL DB) solves the issue.

Enter command line in the MariaDB container:

sudo docker exec -it nxtclouddb bash

Then enter the MySQL instance (MariaDB still uses MySQL commands)

mysql -u root -p

Enter the MySQL root password set in the docker-compose file.

Then run this in the MariaDB server:

SET GLOBAL innodb_read_only_compressed=OFF;

This is also linked in this Reddit post (Wayne links to this as well).

That essentially worked for me so my docker-compose file was set, and with that additional work on the MariaDB container I was able to get to work. For now, my wife and her iPad haven't complained that I know of when backing up files. 

The other nice thing about defining a specific data store (volume) in the container, means you can do other things to back that up with more ease. What I did on the system was run a simple cp -u command to back up the data defined in the volume parameters (the parts in the <> brackets under -volumes) .

Feel free to add you own passwords and local volumes. The docker-compose should bring up a Nextcloud instance without issues beyond the MariaDB issue I just highlighted. I'll try to do a more detailed video on the bring up and advantages of Nextcloud in the near future after some more use. 

Thanks for reading, hope it helps, stay safe, and take care.

*Update and additional notes*

Since creating the video I tried to reproduce these steps in Alpine, Linux Mint and Fedora Silverblue (that using podman-compose, not docker-compose),(see below update) and all failed - at least per the above steps. If you are using the straight-up docker run -d -p 8080:80 nextcloud that should work on all, but docker-compose seems a bit more finicky so Ubuntu worked better out of the box.

Also to note, I did run into some issues with docker getting installed as a Snap in Ubuntu (this happened because I selected to install Docker during the installation of the Ubuntu Server 20.04 VM, but docker-compose is not a snap). That caused me issues after removing the containers manually using docker rm <container name> vs first running docker-compose down. Best in my experience to install both docker and docker-compose using the recommended setup steps from Docker themselves.

All quite technical, but if you are following these steps and want the simplest way to get up an running with Nextcloud, just use Ubuntu 20.04 + Docker + Docker-compose. The above scripts tweaked to your environment and all should work fine.

*Update on Fedora and Podman-compose*  

I persisted a bit longer with Fedora Silverblue as I really like Podman - it just is easy to use out of the box and can run without root access. Over a weekend I poked and prodded a bit more which made me realize I made the same mistake twice now; I forgot about SELinux. Fedora, unlike Ubuntu has SELinux enabled by default. In order to mount a volume in either Podman or Docker, one must waive the SELinux permissions if SELinux if running on the system. It's a simple :z in the volume command, but I had totally overlooked that point. 

Once I added that it worked fine - same work around for mariadb as above (I picked the Docker repositories for the mariadb and nextcloud container images), - but then essentially the same in my limited testing.

Updated the config file for users who may run into SELinux or want SELinux equipped systems.

Modified docker-compsoe for Nextcloud on SELinux systems

Once that is save as a docker-compose.yml file on your directory of choice, and the appropriate data and datadb directories are passed, just run podman-compose up -d similar to Docker. 

Podman-compose works slightly differently in the sense that it creates a pod (group of containers, used in Kubernetes (k8s)) rather than simply a new network for the containers. However, it works fine in this instance and assumingly many others - here is an example with Wordpress. 

For stablity and ease of use, I'd probably still recommend an LTS (long-term support) version of Ubuntu, but I wanted to highlight that podman-compose is also just as capable, and honestly the promises of Silverblue also make it an interesting platform for container workloads like Nextcloud.

Thanks again.