Well, my question is. How to create a file which can start node angular, python main_worker.py, MongoDB and redis? I really do not know where to start.
I just wanna start my web program without opening 7 consoles to start each service like python worker angular node and databases.
I know about angular and MongoDB others are not, will it be your help? try the following ways but you need one console
"scripts": {
"dev": "concurrently \"mongod\" \"ng serve --proxy-config proxy.conf.json --open\" \"tsc -w -p server\" \"nodemon dist/server/app.js\"",
"prod": "concurrently \"mongod\" \"ng build --aot --prod && tsc -p server && node dist/server/app.js\""
},
You can use Docker Compose to start all your services with a single command:
docker-compose up
Learn more about it here: https://docs.docker.com/compose/reference/up/
You will need to create a docker-compose.yml in your project which will looks something like:
version: "3.5"
services:
mongodb:
container_name: mongo
hostname: mongo
image: mongo
restart: always
volumes:
- mongo_data:/var/lib/mongo/data
networks:
- your-app-network
ports:
- 27017:27017
environment:
- YOUR_VARIABLE:value
redis:
container_name: redis
hostname: redis
image: redis
restart: always
volumes:
- rediso_data:/var/lib/redis/data
networks:
- your-app-network
ports:
- 6380:6380
environment:
- YOUR_VARIABLE:value
volumes:
mongo_data:
redis_data:
networks:
go-app:
name: your-app-network
Note, the sample above is not ready to use docker compose file. It just shows you the idea how you do it. You will have to edit it and add some variable and settings specific to your application as well as add more services like node.js, python, etc.
Related
I am deploying a Django project on AWS. I am running Postgres, Redis, Nginx as well as my project on Docker there.
Everything is working fine, but when I change something on my local machine, push changes to git and then pull them on the AWS instance, the code is changing, files are updated but they are not showing on the website. Only the static files are updating automatically (I guess because of Nginx). Here is my docker-compose config:
version: '3.9'
services:
redis:
image: redis
command: redis-server
ports:
- "6379:6379"
postgres:
image: postgres
environment:
- POSTGRES_USER=
- POSTGRES_PASSWORD=
- POSTGRES_DB=
ports:
- "5432:5432"
web:
image: image_name
build: .
restart: always
command: gunicorn project.wsgi:application --bind 0.0.0.0:8000
env_file:
- envs/.env.prod
ports:
- "8000:8000"
volumes:
- ./staticfiles/:/tmp/project/staticfiles
depends_on:
- postgres
- redis
nginx:
image: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./staticfiles:/home/app/web/staticfiles
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/logs:/var/log/nginx
- ./certbot/www:/var/www/certbot/:ro
- ./certbot/conf/:/etc/nginx/ssl/:ro
depends_on:
- web
Can you please tell me what to do?
I tried deleting everything from docker and compose up again but nothing happened.
I looked all over in here but I still don't understand... instance restart is not working as well. I tried cleaning redis cache because I have template caching and still nothing.
After updating the code on the EC2 instance, you need to build a new web docker image from that new code. If you are just restarting things then docker-compose is going to continue to pick up the last docker image you built.
You need to run the following sequence of commands (on the EC2 instance):
docker-compose build web
docker-compose up -d
You are seeing the static files change immediately, without rebuilding the docker image, because you are mapping to those files via docker volume.
I found the issue... it was because I had template caching.
If I remove the cache and do what #MarkB suggested, all is updating.
I don't understand why this happens since I tried flushing all redis cache after changes but I guess it solves my issues.
I have two separate Docker containers, and separate docker-compose YAML's, too. One ('mongodb') for running the MongoDB, the other ('logger') for data scraping in Python. The latter should write some results into MongoDB.
I used separate yaml's to be able to stop easily one container while not stopping the other one.
To resolve this task I used docker-compose' bridge network capability. So I used the following two yaml's:
networks:
wnet:
driver: bridge
services:
mongodb:
image: mongo:4.0.9
container_name: mongodb
ports:
- "27018:27017"
volumes:
- mongodb-data:/data/db
logging: *default-logging
restart: unless-stopped
networks:
- wnet
volumes:
mongodb-data:
name: mongodb-data
and
networks:
wnet:
driver: bridge
services:
logger:
build:
context: .
image:logger:$VERSION
container_name:logger
environment:
- TARGET=$TARGET
volumes:
- ./data:/data
restart: unless-stopped
networks:
- wnet
The Python container should now persist the scraped data within the MongoDB database. So I tried the following variants:
from pymongo import MongoClient
client = MongoClient(port=27018, host='mongodb') # V1
client = MongoClient(port=27018) # V2
db = client['dbname']
Then, executing one of the following commands throws the error:
db.list_collection_names()
db.get_collection('aaa').insert_one({ 'a':1 })
The response I get is
pymongo.errors.ServerSelectionTimeoutError: mongodb:27018: [Errno -2] Name or service not known
Any idea?
Thanks.
What finally worked is to refer to the network (defined in container mongodb) by its composed name (mongodb + wnet = mongodb_wnet), and to add the external option. This makes the YAML file of the logger container look like:
services:
logger:
build:
context: .
image: logger:$VERSION
container_name: logger
environment:
- TARGET=$TARGET
volumes:
- ./data:/data
restart: unless-stopped
networks:
- mongodb_wnet
networks:
mongodb_wnet:
external: true
However, as mentioned by #BellyBuster, it might be a good idea to use one single docker-compose file. I was not aware that it is quite easy to start, stop, and build single containers belonging to the same YAML.
SO has also enough posts on that, e.g. How to restart a single container with docker-compose and/or docker compose build single container.
I have two services, on two different GitLab repositories, deployed to the same host. I am currently using supervisord to run all of the services. The CI/CD for each repository pushes the code to the host.
I am trying to replace supervisord with Docker. What I did was the following:
Set up a Dockerfile for each service.
Created a third repository with only a docker-compose.yml, that runs docker-compose up in its CI to build and run the two services. I expect this repository to only be deployed once.
I am looking for a way to have the docker-compose automatically update when I deploy one of the two services.
Edit: Essentially, I am trying to figure out the best way to use docker-compose with a multi repository setup and one host.
My docker-compose:
version: "3.4"
services:
redis:
image: "redis:alpine"
api:
build: .
command: gunicorn -c gunicorn_conf.py --bind 0.0.0.0:5000 --chdir server "app:app" --timeout 120
volumes:
- .:/app
ports:
- "8000:8000"
depends_on:
- redis
celery-worker:
build: .
command: celery worker -A server.celery_config:celery
volumes:
- .:/app
depends_on:
- redis
celery-beat:
build: .
command: celery beat -A server.celery_config:celery --loglevel=INFO
volumes:
- .:/app
depends_on:
- redis
other-service:
build: .
command: python other-service.py
volumes:
- .:/other-service
depends_on:
- redis
If you're setting this up in the context of a CI system, the docker-compose.yml file should just run the images; it shouldn't also take responsibility for building them.
Do not overwrite the code in a container using volumes:.
You mention each service's repository has a Dockerfile, which is a normal setup. Your CI system should run docker build there (and typically docker push). Then your docker-compose.yml file just needs to mention the image: that the CI system builds:
version: "3.4"
services:
redis:
image: "redis:alpine"
api:
image: "me/django:${DJANGO_VERSION:-latest}"
ports:
- "8000:8000"
depends_on:
- redis
celery-worker:
image: "me/django:${DJANGO_VERSION:-latest}"
command: celery worker -A server.celery_config:celery
depends_on:
- redis
I hint at docker push above. If you're using Docker Hub, or a cloud-hosted Docker image repository, or are running a private repository, the CI system should run docker push after it builds each image, and (if it's not Docker Hub) the image: lines need to include the repository address.
The other important question here is what to do on rebuilds. I'd recommend giving each build a unique Docker image tag, a timestamp or a source control commit ID both work well. In the docker-compose.yml file I show above, I use an environment variable to specify the actual image tag, so your CI system can run
DJANGO_VERSION=20200113.1114 docker-compose up -d
Then Compose will know about the changed image tag, and will be able to recreate the containers based on the new images.
(This approach is highly relevant in the context of cluster systems like Kubernetes. Pushing images to a registry is all but required there. In Kubernetes changing the name of an image: triggers a redeployment, so it's also all but required to use a unique image tag per build. Except that there are multiple and more complex YAML files, the overall approach in Kubernetes would be very similar to what I've laid out here.)
I am running a python application as a docker container and in my python application I am using pythons logging class to log execution steps using logger.info, logger.debug and logger.error. The problem with this is the log file is only persistent within the docker container and if the container goes away then the log file is also lost and also that every time I have to view the log file I have to manually copy the container log file to local system.What I want to do is that whatever log is being written to container log file, it should be persistent on the local system - so write to a local system log file or Auto mount the docker log file to local system.
Few things about my host machine:
I run multiple docker containers on the machine.
My sample docker-core file is:
FROM server-base-v1
ADD . /app
WORKDIR /app
ENV PATH /app:$PATH
CMD ["python","-u","app.py"]
My sample docker-base file is:
FROM python:3
ADD ./setup /app/setup
WORKDIR /app
RUN pip install -r setup/requirements.txt
A sample of my docker-compose.yml file is:
`
version: "2"
networks:
server-net:
services:
mongo:
container_name: mongodb
image: mongodb
hostname: mongodb
networks:
- server-net
volumes:
- /dockerdata/mongodb:/data/db
ports:
- "27017:27017"
- "28017:28017"
server-core-v1:
container_name: server-core-v1
image: server-core-v1:latest
depends_on:
- mongo
networks:
- server-net
ports:
- "8000:8000"
volumes:
- /etc/localtime:/etc/localtime:ro
`
Above yml file sample is just a part of my actual yml file. I have multiple server-core-v1 containers(with different names) running parallel with each having their own logging file.
I would also appreciate if there are some better strategies for doing logging in python with docker and make it persistent. I read few articles which mentioned using sys.stderr.write() and sys.stdout.write() but not sure how to use that especially with multiple containers running and logging.
Volumes are what you need.
You can create volumes to bind an internal container folder with a local system folder. So that you can store your logs in a logs folder and map this as a volume to any folder on your local system.
You can specify a volume in the docker-compose.yml file for each service you are creating. See the docs.
Bind-mounts are what you need.
As you can see, bind-mounts are accesible from yours host file system. It is very simmilar to shared folders in VM architecture.
You can simple achieve that with mounting your volume directly to path on your PC.
In yours case:
version: "2"
networks:
server-net:
services:
mongo:
container_name: mongodb
image: mongodb
hostname: mongodb
networks:
- server-net
volumes:
- /dockerdata/mongodb:/data/db
ports:
- "27017:27017"
- "28017:28017"
server-core-v1:
container_name: server-core-v1
image: server-core-v1:latest
depends_on:
- mongo
networks:
- server-net
ports:
- "8000:8000"
volumes:
- ./yours/example/host/path:/etc/localtime:ro
Just replace ./yours/example/host/path with target directory on yours host.
In this scenario, i belive that logger is on server side.
If you are working on windows remember to bind in current user directory!
I am using docker-compose to deploy multiple microservices in flask. Here is the compose code
version: '3'
services:
test-api:
volumes:
- ./test-api:/test-api
build: test-api
ports:
- "5000:5000"
redis:
image: "redis:alpine"
search:
volumes:
- ./seach:/search
environment:
- HTTP_PORT=5000
- REDIS_URL=redis://redis:6379/0
build: search
ports:
- "5001:5000"
link:
- redis
Now I have to access this service from single URL eg: http://example.com/test-api or http://example.com/search, but I am unable to figure it out since the 2 services are running are on 2 different ports. I know I need to use nginx and configure it so that I can access them. But I am not sure how to do that. Can someone help me with this or at least give me some docs to read so as to understand the routing?
Also both the services use /health to report the result of health-check. How do I access the health check for both the services?
As you wrote you should use a load balancer placed in front of your services. Now, you should create a docker network without exposing ports. the only container that exposes ports should be the nginx container in order to handle all clients request. The test-api, search and nginx should be part of the same docker network in order to allow nginx to dispatch the request to the right container. Your docker-compose file should look like this:
version: '3'
services:
loadbalancer:
image: nginx
ports:
- "80:8080"
networks:
- my_netowrk
test-api:
volumes:
- ./test-api:/test-api
build: test-api
networks:
- my_netowrk
redis:
image: "redis:alpine"
networks:
- my_netowrk
search:
volumes:
- ./seach:/search
environment:
- HTTP_PORT=5000
- REDIS_URL=redis://redis:6379/0
build: search
networks:
- my_netowrk
networks:
my_netowrk:
driver: <driver>
I would advise you to don't use links anymore, they are old and deprecated.
You can learn more about docker networks from links below:
https://docs.docker.com/network/
https://docs.docker.com/compose/networking/
https://docs.docker.com/compose/compose-file/#network-configuration-reference
So for the people who are looking for a quick solution, here is my nginx file
http {
server {
listen 80;
location /test {
proxy_pass http://test-api:5000;
}
location /search {
proxy_pass http://search:5000;
}
location /health-test {
proxy_pass http://test-api:5000/health;
}
location /health-search {
proxy_pass http://search:5000/health;
}
}
}