docker build . -t localhost:32000/mongo-app:v1
8) test the image using port forwarding:
docker run -p 3000:3000 localhost:32000/mongo-app:v1
docker push localhost:32000/mongo-app:v1
microk8s.kubectl get pod -o wide
Congratulations!
Various tutorials from programming to system administration. Topics include docker, javascript, angular, ubuntu, php and many others.
References: Docker for web developers course.
build: ./
image: webapp:tag
webapp
, tagged tag
RUN
command that installed the packages.
Otherwise, the deleted files will be gone in the latest layer, but not from the previous layer.
COPY
the dependency lists (package.json, composer.json, requirements.txt, etc.) to the container in order for Docker to cache the results of the npm install
that follows. This way when changing other parts of the container configuration and re-building it, docker will not rebuild
all the dependencies, but use the cached ones. At the same time, if we change a line inside the dependencies list file, all the dependencies will be re-installed, because they now form another different cached layer inside of docker.npm/composer install
).version: "3.8" services: web: image: nginx:alpine volumes: - type: volume # named volume source:
dbdata # link to created volume inside of container
target: /data # inside of container - type: bind # bind mount source: ./static # local directory target: /app/static # inside of container
volumes: dbdata: #
create volume inside of container
Note: anonymous volumesvolumes:
- '.:/app' # bind mount - copy the local host dir into container at runtime
- '/app/node_modules' # anonymous volume - preserve container built /node_modules at runtime
version: '3'
services:
service1:
build: # note: we are in build phase
context: ./
args:
USER_VAR: 'USER1' # setup the USER_VAR variable
# note: if there is alredy USER_VAR inside the alpine image (used in the Dockerfile)
# it will overrite the USER_VAR and show instead
Dockerfile:
FROM alpine
# note accessing the USER_VAR after the FROM line !
ARG USER_VAR # access the docker-compose set USER_VAR
RUN echo "variable is: $USER_VAR" # echo on screen
ENV_USER_VAR = USER1docker-compose:
version: '3'
services:
service1:
build: # note: we are in build phase
context: ./
args:
USER_VAR: ${ENV_USER_VAR} # setup the USER_VAR variable from .env file
Dockerfile:FROM alpine
ARG USER_VAR # access the docker-compose set USER_VAR
RUN echo "variable is: $USER_VAR" # echo on screen
Example secrets:docker secret create mysql_root_password ./
db_root_password.txt
docker secret create db_password ./
db_password.txt
docker secret ls
version: '3.1'
services:
db:
image: mysql:8
volumes:
- db_data:/var/lib/mysql # using persistant volume inside the container
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/
mysql_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
# read the password from memory and set the container environment variable
MYSQL_PASSWORD_FILE: /run/secrets/db_password
secrets:
-
mysql_root_password
# enable access to the in-memory secrets
- db_password
# enable access to the in-memory secrets
secrets:
db_password:
#
Docker mounts the db_password.txt file under /run/secrets/db_password
file: db_password.txt #read the password from db_password.txt file in-memory filesystem
# note: if a container stops running, the secrets shared to it are
unmounted from the in-memory filesystem and flushed from the node’s memory.
mysql_root_password
:
file:
mysql_root_password
.txt
volumes:
db_data:
# creating persistant volume inside the container
ps -aef --forest|grep apache2
root /usr/sbin/apache2 -k startUSER node RUN npm install
0) set initial ownership of /var/www/html to the current user/developersudo chown -R $USER:www-data /var/www/html
1) user www-data(apache) can only read files(+r) and directories(+rx)sudo find /var/www/html -type d -exec chmod g+rx {} +
sudo find /var/www/html -type f -exec chmod g+r {} +
sudo chown -R USER /var/www/html/
sudo find /var/www/html -type d -exec chmod u+rwx {} +
sudo find /var/www/html -type f -exec chmod u+rw {} +
sudo chmod -R o-rwx /var/www/html/
chmod g+s .
set the group ID (setgid) on the current directory - all newly created files and subdirectories will inherit the current group ID, rather than the group ID of the user creator.PRODUCTION: using local-dev project files and building dependencies inside the container
dockerfile# 1st stage
FROM composer AS builder
COPY composer.* /app # copy local app dependencies into the container /app directory
RUN composer install --no-dev # build project dependencies in container's /vendor folder in order container to build its own dependencies excluding dev-dependencies
# 2nd stage
FROM php:7.4.5-apache as base #start a new build stage with the
php-apache
image as its base
RUN docker-php-ext-install mysqli
# Note:COPY
copies just the built artifact from previous stage to a new stage.
COPY --from=base ./ /var/www/html/ # copy our local project files inside the container using the base stage COPY --from=builder /app/vendor/var/www/html/vendor/
#from the composer stage copy the pre-build vendor folder to the container
docker-compose.yaml
version: '3.7'
services:
app:
build: .
target: base # we just run the build phase only when the target is base
# i.e. don't need to rebuild the 1st stage of the build (composer install)
ports:
- 80:80
volumes:
- ./:/var/www/html # getting bind mount inside of the container to local development directory
- /var/www/html/vendor # preserving container's built dependencies from being overwritten by bind mount
DEVELOPMENT: using both local-dev project files and dependencies (we need to manually install dependencies using composer install)dockerfileversion: '3.7'FROM php:7.4.5-apache as base #start a new build stage with the
php-apache
image as its base
RUN docker-php-ext-install mysqli
# Note:COPY
copies just the built artifact from previous stage to a new stage.
COPY ./ /var/www/html/ # copy our local project files inside the container using the base stage
docker-compose.yaml
services:
app:
build: .
ports:
- 80:80
volumes:
- ./:/var/www/html # getting bind mount inside of the container to local development directory
FROM node AS build
WORKDIR /usr/src/app # created / bind-mount volume inside the compose file
COPY package.json .
RUN npm install # install the app package dependencies
COPY . ./src # copy generated code into the container
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from build /usr/src/app/build /usr/share/nginx/html
docker-compose.yaml
FROM php:7.4-fpm-alpine as base FROM base as development
# build development environment
FROM base as production COPY data /var/www/html # copy into the container the generated source files
php-dev: build: .
target: development ports: - "9000:9000"
php-prod: build: .
target: production ports: - "9000:9000"
volumes:
- ./:/var/www/html
docker build . -t app-dev --target=development
docker build . -t app-prod --target=production
FAQ:
How to inspect containers:
Here is how to inspect the open ports inside of both MySQL and Apache containers.
1) we need to get get the running container process id:
docker container ls (to get the container_id)
then:
docker inspect -f '{{.State.Pid}}' <container_id>
2) having the container process_id run netstat inside the container namespace:
sudo nsenter -t <container_process_id> -n netstat
which will show us which ports are open for connections from outside world to the container.
If needed you can also start a temporary shell in the container: docker exec -it <container_id> /bin/bash and try to analyze what is happening: i.e missing file/directory permissions with ls -la, check the container logs etc..., like when you are running the Apache server locally. For example you can easily check on which port Apache server is running with: sudo netstat -anp | grep apache2 , sudo lsof -i -P | grep apache2 , or cat /etc/apache2/ports.conf Then having the right port update your docker container configuration: delete and rebuild the container.
Enable / disable PHP extensions:
It is possible with: RUN docker-php-ext-install name_of_extension
Note: some extensions require additional system libraries to be also installed. For exmaple for the zip library you need to run on the same line before php-ext-install...: apt-get install libzip-dev zlib1g-dev;
How to import database from local drive into a mariadb/mysql database:
If the container is already present, execute the following commands: docker exec -i mysql8 mysql -udevuser -pdevpass mysql < db_backup.sql
or docker exec -i mysql8 sh -c 'exec mysql -udevuser -pdevpass' < db_backup.sql
Of course, you can just mount a local database (bind mount) to be used within the container with: docker run -v /var/lib/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root mysql8
How to create tables inside of a mysql container?
You can create a sample table with the help of php:
$sql = "CREATE TABLE MyTable (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(30) NOT NULL,
email VARCHAR(50),
reg_date TIMESTAMP
)";
if ($conn->query($sql)===TRUE) { echo "Table MyTable created successfully"; }
How to copy a local folder from /var/www/html/folder_name to folder html inside a docker container?
COPY /var/www/html/folder_name /app
How to create a persistent volume and link the container to use it?
dockerfile:
FROM php:7.4-apache
COPY --chown=www-data:www-data . /var/www/html # we copy the current directory contents into /var/www/html directory inside of the container
docker-compose.yaml
version: '3.8'
services:
php:
build: ./ # use the above dockerfile to create the image
ports:
- 8080:80
volumes:
- type: volume
source: phpdata
target: /var/www/html
volumes:
phpdata:
How can you dockerize a website and then run the containers on another server?
First create a backup of the current container images and their content:
1) commit the changes made so far in the container: docker commit container_id backup_image_name
2) save the image to your local(node) machine: docker save backup_image_name > backup_image.tar
On the second server restore the image via:
1) docker load < backup_image.tar
2) start a container/s using the backup_image
Please not that if you have bind mounts (or volumes that reside outside of the container), you need to backup them manually!
How to install phpmyadmin?
docker-compose.yml file:
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
env_file: .env
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
ports:
- 3333:80
.env file:
MYSQL_ROOT_PASSWORD = the password from the MYSQL installation
How to use local domains to access the container like domain.local?
You can start a NEW container from an image specifying -h (hostname option): docker run -h domain.local
How to forward localhost:8000 to some_domain.com
You can create an Nginx reverse-proxy container, which will expose your service container when browsing the Nginx container at port 80. Let's suppose you have a "web" service defined inside a docker-compose.yaml file.
1) Nginx configuration
default.conf
server {
listen 80;
listen [::]:80; # listen for connections on port 80
server_name web-app.localhost;
location / {
proxy_pass http://web:80; #web is the name of the service(container) you would like to expose, 80 is the port, the service is listening on
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
2) Dockerfile image configuration:
FROM nginx
COPY default.conf /etc/nginx/conf.d/
3) create an entry in hosts file pointing to
127.0.0.1 web-app.localhost
You can now browse: http://web-app.localhost
Congratulations and enjoy the Docker course !
Installing XDebug under VSCode is not a very easy task, especially under the Docker environment. Here is my way of doing it. References: Docker for web developers course.
https://github.com/laravel/laravel.git .
MYSQL_ROOT_PASSWORD=mysql_root
MYSQL_ROOT=wp_user
MYSQL_PASSWORD=wp_password
version: '3.3'
services:
db:
image: mysql:latest
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: --default-authentication-plugin=mysql_native_password
wordpress:
depends_on:
- db
image: wordpress:latest
env_file: . env
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
ports:
- "80:80"
phpmyadmin:
depends_on:
- db
image: phpmyadmin/phpmyadmin:latest
env_file: .env
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
ports:
- 3333:80
volumes:
wordpress:
dbdata:
For more information, you can check the Docker for web developers course.
First, we will install docker and docker-compose:
sudo apt install docker docker-compose
Then we will create docker group and place our user inside(to be able to use the docker command without sudo):
sudo groupadd docker && sudo usermod -aG docker $USER
Now we either exit and re-run the terminal or type:
newgrp docker
to switch our group.
Let's check the current images we are having: from docker image ls. We can test if docker's installation is successful with:
docker run hello-world
Keep in mind that we can check what images we have in our system via:
docker image ls
and our containers via
docker container ls
With docker
rmi hello-world: latest
we will remove the just installed image, but only if it is empty.
Let's check once again
docker container ls -a
which will list all the images: running or not. We see our image is placed inside a container.
As a rule: if we want to remove an image, first we have to remove its container.
So we look up the container name. It is usually assigned by docker and in our case is: relaxed_cray and then we type
docker container rm relaxed_cray
Now we can remove the image with
docker rmi hello-world:latest
Setting up the PHP development environment
We will make a directory web_dev :
mkdir web_dev
and will go inside:
cd web_dev
Then we will create docker-compose file with:
nano docker-compose.yml
Inside we will place the following config:
Keep in mind that for the indentations we are using 2 spaces!
services:
web:
image: php:8.1-apache
container_name: php81
volumes:
- ./php:/var/www/html/
ports:
- 8008:80
sudo chown your_user:your_user php/ -R
sudo nano index.php
we can type inside:<?php
Then again run docker-compose up. Also, try changing the .php file again and refresh the browser pointing to 127.0.0.0:8008echo "Hello from docker";
?>
FROM php:8.1-apache
RUN apt-get update && apt-get upgrade -y RUN docker-php-ext-install mysqli
EXPOSE 80
buid:
context: ./php
dockerfile: Dockerfile
db:
container_name: mysql8
image: mysql:latest
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test_db
MYSQL_USER: devuser
MYSQL_PASSWORD: devpass
ports:
- 6033:3306
depends_on:
- db
$host = 'db'; //the name of the mysql service inside the docker file.
$user = 'devuser';
$password = 'devpass';
$db = 'test_db';
$conn = new mysqli($host,$user,$password,$db){
if($conn->connect_error){
echo 'connection failed'. $conn->connect_error;
}
echo 'successfully connected to MYSQL';
}
docker image ls -a
docker rmi image ...fill here image names...
then run again docker-compose up and browse: 127.0.0.1:8008sudo apt update && sudo apt install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"Note: if you are running an unsupported Ubuntu release you can replace the string: $(lsb_release -cs) with the supported versions such as: disco
sudo apt update && sudo apt install docker-ce docker-ce-cli containerd.io
sudo docker run hello-worldFor more information, you can visit: https://docs.docker.com/install/linux/docker-ce/ubuntu/
In this guide, we’ll walk through setting up a local AI-powered coding assistant within Visual Studio Code (VS Code). By leveraging tools s...