docker network
引子
https://github.com/fanqingsong/fastapi-react-postgres-keycloak-sso
docker compose 配置文件定义了若干service
version: "3" services: nginx: image: nginx:1.17 volumes: - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf - ./logs/nginx:/var/log/nginx ports: - 80:80 depends_on: - frontend - backend backend: restart: unless-stopped build: context: backend dockerfile: Dockerfile env_file: - .env environment: PYTHONPATH: . DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_USER} volumes: - ./logs/backend:/logs ports: - 8888:8888 depends_on: - postgres - keycloak frontend: build: context: frontend dockerfile: Dockerfile ports: - 8000:8000 environment: NODE_ENV: development CHOKIDAR_USEPOLLING: "true" keycloak: image: jboss/keycloak:12.0.4 environment: DB_VENDOR: POSTGRES DB_SCHEMA: public DB_ADDR: keycloak_postgres DB_DATABASE: ${KEYCLOAK_DB_DATABASE} DB_USER: ${KEYCLOAK_DB_USER} DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD} KEYCLOAK_USER: ${KEYCLOAK_ADMIN_USERNAME} KEYCLOAK_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD} JDBC_PARAMS: "useSSL=false" ports: - 8080:8080 depends_on: - keycloak_postgres postgres: image: postgres restart: always environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - 5432:5432 volumes: - postgres_data:/var/lib/postgresql/data keycloak_postgres: image: postgres volumes: - keycloak_postgres_data:/var/lib/postgresql/data environment: POSTGRES_DB: ${KEYCLOAK_DB_DATABASE} POSTGRES_USER: ${KEYCLOAK_DB_USER} POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD} volumes: postgres_data: keycloak_postgres_data:
nginx反向代理可以直接使用service的名称做代理转发
一般网络访问使用域名或者IP访问网络资源,
什么机制可以支撑使用服务名来访问容器资源?
需要从docker的网络机制说起。
server { listen 80; listen [::]:80; server_name _; location / { proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://frontend:8000; access_log /var/log/nginx/access_frontend.log; error_log /var/log/nginx/error_frontend.log; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /api { access_log /var/log/nginx/access_backend.log; error_log /var/log/nginx/error_backend.log; proxy_pass http://backend:8888/api; } }
docker network
https://docs.docker.com/network/
最常使用的三种网络类型
bridge -- 支持单机上的容器互相访问
host -- 支持容器直击使用主机的网络资源, port+IP
overlay -- 支持跨主机的分布式容器互相访问
Network drivers
Docker’s networking subsystem is pluggable, using drivers. Several drivers exist by default, and provide core networking functionality:
bridge
: The default network driver. If you don’t specify a driver, this is the type of network you are creating. Bridge networks are usually used when your applications run in standalone containers that need to communicate. See bridge networks.
host
: For standalone containers, remove network isolation between the container and the Docker host, and use the host’s networking directly. See use the host network.
overlay
: Overlay networks connect multiple Docker daemons together and enable swarm services to communicate with each other. You can also use overlay networks to facilitate communication between a swarm service and a standalone container, or between two standalone containers on different Docker daemons. This strategy removes the need to do OS-level routing between these containers. See overlay networks.
bridge tutorial
https://docs.docker.com/network/network-tutorial-standalone/
host tutorial
https://docs.docker.com/network/network-tutorial-host/
overlay tutorial
https://docs.docker.com/network/network-tutorial-overlay/
networking practice on docker
https://docs.docker.com/get-started/07_multi_container/
Multi container apps
Up to this point, you’ve been working with single container apps. But, now you will add MySQL to the application stack. The following question often arises - “Where will MySQL run? Install it in the same container or run it separately?” In general, each container should do one thing and do it well. The following are a few reasons to run the container separately:
- There’s a good chance you’d have to scale APIs and front-ends differently than databases.
- Separate containers let you version and update versions in isolation.
- While you may use a container for the database locally, you may want to use a managed service for the database in production. You don’t want to ship your database engine with your app then.
- Running multiple processes will require a process manager (the container only starts one process), which adds complexity to container startup/shutdown.
And there are more reasons. So, like the following diagram, it’s best to run your app in multiple containers.
networking on compose
https://docs.docker.com/compose/networking/
与前节对比, compose就是对docker 网络原语的封装。
如果没有指定网络, 则会创建默认bridge网络,所有的业务的容器工作在此默认网络中
For example, suppose your app is in a directory called
myapp
, and yourdocker-compose.yml
looks like this:services: web: build: . ports: - "8000:8000" db: image: postgres ports: - "8001:5432"
When you run
docker compose up
, the following happens:
- A network called
myapp_default
is created.- A container is created using
web
’s configuration. It joins the networkmyapp_default
under the nameweb
.- A container is created using
db
’s configuration. It joins the networkmyapp_default
under the namedb
.Each container can now look up the hostname
web
ordb
and get back the appropriate container’s IP address. For example,web
’s application code could connect to the URLpostgres://db:5432
and start using the Postgres database.It is important to note the distinction between
HOST_PORT
andCONTAINER_PORT
. In the above example, fordb
, theHOST_PORT
is8001
and the container port is5432
(postgres default). Networked service-to-service communication uses theCONTAINER_PORT
. WhenHOST_PORT
is defined, the service is accessible outside the swarm as well.Within the
web
container, your connection string todb
would look likepostgres://db:5432
, and from the host machine, the connection string would look likepostgres://{DOCKER_IP}:8001
for examplepostgres://localhost:8001
if your container is running locally.
也可以做更细的网络划分
services: proxy: build: ./proxy networks: - frontend app: build: ./app networks: - frontend - backend db: image: postgres networks: - backend networks: frontend: # Use a custom driver driver: custom-driver-1 backend: # Use a custom driver which takes special options driver: custom-driver-2 driver_opts: foo: "1" bar: "2"