# Learning Docker for myself (1) - Single Docker
## Study notes mainly based on https://docker-curriculum.com
## Prerequisites
Please follow the "Getting Started" section of the [site](https://docker-curriculum.com/#getting-started)
## Basic commands
### pull
<font color="#f00">`pull`</font> fetches the busybox image from the Docker registry and saves it to our system.
Use `busybox` image as the example
```console
$ docker pull busybox
```
### images
<font color="#f00">`images`</font> command to see a list of all images on your system. Same as `image ls`
```console
$ docker images
$ docker image ls
```
### run
<font color="#f00">`run`</font> could initial a Docker container based on this image.
The container booted up, ran an empty command and then exited. Expecting no output from first command, the second command export "hello from busybox"
```console
$ docker run busybox
$ docker run busybox echo hello from busybox
```
<font color="#f00">`docker run -it [cotainer] sh`</font> attaches us to an interactive tty (terminal type) in the container. Now we can run as many commands in the container as we want. Meaning that we are accessing the container's shell. Enter <font color="#f00">`$ exit`</font> to leave the attached terminal.
```console
$ docker run -it busybox sh
/ # ls
bin dev etc home proc root sys tmp usr var
/ # uptime
05:45:21 up 5:58, 0 users, load average: 0.00, 0.01, 0.04
```
### ps/ls (list container(s))
<font color="#f00">`ps`</font> how many containers that is up and running. Same as <font color="#f00">`container ls`</font>.
```console
$ docker ps # Only listing the running container(s)
$ docker ps -a #Give more detail, incluing existed container(s)
```
### rm (remove)
<font color="#f00">`docker rm [container-id-1/name-2] [container-id-2/name-2`</font> remove specific container(s)
`--rm` flag that can be passed to docker run which automatically deletes the container once it's exited from.
```console
$ docker run --rm busybox
```
### prune (clean stoped container)
<font color="#f00">`docker container prune`</font> remove all the stopped container
```console
$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
4a7f7eebae0f63178aff7eb0aa39f0627a203ab2df258c1a00b456cf20063
f98f9c2aa1eaf727e4ec9c0283bcaa4762fbdba7f26191f26c97f64090360
Total reclaimed space: 212 B
```
### rmi (remove images)
<font color="#f00">`docker rmi [image-id-1] [image-id-2/name-2]`</font>
```console
$ docker rmi busybox
```
### stop
<font color="#f00">`docker stop [container-name]`</font>
```console=
$ docker stop static-site
```
---
## WEB APP with docker (Static Site)
### First inital
The command below the `--rm` flag automatically removes the container when it exits and the `-it` flag specifies an interactive terminal which makes it easier to kill the container with Ctrl+C
```console
docker run --rm -it prakhar1989/static-site
```
Since we have no port exposed, there are not way we could access this container.
Hit Ctrl+C to stop the container.
<font color="#f00">**Note**</font>: Not sure if this is apple silicon chip only, but if you see error message ++The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested++ please add `--platform=linux/amd64`
e.g.
```console
$ docker run --platform=linux/amd64 --rm -it prakhar1989/static-site
```
<font color="#f00">**Note**</font>: You will also see the error ++iosetup() failed (38: Function not implemented)++, it is also caused by M1 chips conflict with nginx and could be safely ignored for the rest of the demo.
### Exposing random ports
In the follwing commands, <font color="#f00">`-d`</font> will detach our terminal, <font color="#f00">`-P`</font> will publish all exposed ports to random ports and finally <font color="#f00">`--name`</font> corresponds to a name we want to give.
```console
$ docker run --platform=linux/amd64 -d -P --name static-site prakhar1989/static-site
```
Followed by <font color="#f00">docker port [CONTAINER]</font>
```console
$ docker port static-site
80/tcp -> 0.0.0.0:32769 # actual port is randomed as we had flag -P
443/tcp -> 0.0.0.0:32768
```
and the site could be accessed via http://localhost:32769
### Exposing custom port
A custom port could be specify which the client will foward the connections to the conainer
```console
$ docker run --platform=linux/amd64 -d -p 5003:80 --name static-site prakhar1989/static-site
```
and the site could be accessed via http://localhost:5003
Stop the container by
```console
$ docker stop static-site #static-site as the name we given
static-site
```
## Docker images
### Creating Dockerfile
The Flask app below will display random cat .gif. Do clone it to the machine that is running the docker commands
```console
$ git clone https://github.com/prakhar1989/docker-curriculum.git
$ cd docker-curriculum/flask-app
```
In the repository we cloned above, it contain a Dockerfile in the flask-app directory. Almost same as below (Added some comments here to future explain the function of each lines)
```dockerfile
FROM python:3.8
# set a directory for the app, as the working directory
WORKDIR /usr/src/app
# copy all the files to the container
# The First argument "." is the local current directory.
# The Second argument "." is the working dictory, in which the conainer will consider as "current directory". in this case: /usr/src/app
COPY . .
# install dependencies
# --no-cache-dir will not stored the pip cache (the downloaded file for future use) to save space
# -r install from the given requirments file
RUN pip install --no-cache-dir -r requirements.txt
# tell the port number the container should expose
EXPOSE 5000
# run the command
CMD ["python", "./app.py"]
```
### Build the image
Execute the command below, it may take a while. Once you see 'Successfully built' means it is done.
```console
$ docker build -t yourusername/catnip . ## Do update the 'yourusername' to your Docker hub user name. Don't forgot the . at the end
```
Once the the image build successfully, execute the command:
```console
$ docker run -p 8888:5000 yourusername/catnip
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://172.17.0.3:5000
```
The command we just ran used port 5000 for the server inside the container and exposed this externally on port 8888. You could now user your browser to access the app with url: http://127.0.0.1:8888
### Push your image
First, login to the docker hub. You should see 'login Successed' after login
```console
$ docker login
Login in with your Docker ID to push and pull images from Docker Hub. If you do not have a Docker ID, head over to https://hub.docker.com to create one.
Username: yourusername
Password: yourpassword
WARNING! Your password will be stored unencrypted in /Users/yourusername/.docker/config.json
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/credential-store
login Succeeded
```
<font color="#f00">**Note**</font>: Not sure if this is apple silicon chip only. Before you processed to the next step, rebuild your image as following:
```
$ docker build --platform linux/amd64 -t yourusername/catnip:linux_amd64 .
```
This is because that the AWS service we are going to use will take this platform instead of the default platform, the ":linux_amd64" is the tag we add to specify the build.
Now push the image to the hub:
```
$ docker push yourusername/catnip:linux_amd64
```
After success, the others could use following commands to pull and run your image!
```
$ docker run -p 8888:5000 yourusername/catnip:linux_amd64
```
## AWS Beanstalk(EB)
We will use EB to deploy our single-container Docker, [create an AWS account](https://aws.amazon.com/) if you havn't.
Credit card info is needed but anything we opereated during this notes will be free.
1. Sign in to [AWS console](https://aws.amazon.com/console/)
2. Click on Elastic Beanstalk. It will be in the compute section on the top left. Alternatively, you can access the [Elastic Beanstalk console](https://ap-northeast-1.console.aws.amazon.com/elasticbeanstalk/home?region=ap-northeast-1#/welcome), and click the "Create Applicaton"

3. Have a unique Application name you want for your application, and follow the setting in the image (You could give it a Version label you want)
4. Find the <font color="#f00">`Dockerrun.aws.json`</font> where locate in the flask-app folder and the it should be look like image below, do remeber to modify the Name as your name and image you built and pushed eariler.
```jsonld
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "yourusername/catnip:linux_amd64",
"Update": "true"
},
"Ports": [
{
"ContainerPort": 5000,
"HostPort": 8000
}
],
"Logging": "/var/log/nginx"
}
```
5. Click the Choose file and uploaded your modifed <font color="#f00">`Dockerrun.aws.json`</font>. Click "Create application". The whole process will take a while.
6. Once completed, you will see the page as following:
7. Click the red arrow pointed link and witness the glory of cats!
8. Once you done the cats sharing, now to clean up in case we receive the real bill. Click the Terminated Environment in the action menu and follow the instruction to terminate the environment. This will take a while as well. You can check the "Environments" in the naviation section and see the (terminated) at the end of your environment name and you are good
-----
## Reference
###### tags: `Docker` `AWS`