├── 9_YAML
├── img
│ ├── yaml.png
│ ├── yaml1.png
│ ├── yaml2.png
│ ├── yaml_spaces.png
│ ├── yaml_specials.png
│ └── data_types_yaml.png
└── YAML.md
├── 1_introduction
├── img
│ └── hi_alex.png
├── 2how_to_begin_to_wrork_with_docker.md
├── 3demo_how_to_install_docker_on_linux.md
└── 1docker_review.md
├── 2_docker_commands
├── img
│ ├── docker_ps.png
│ ├── docker_ps2.png
│ ├── docker_rm.png
│ ├── docker_rmi.png
│ ├── nginx_conf.png
│ ├── docker_attach.png
│ ├── docker_exec.png
│ ├── docker_images.png
│ ├── docker_ps-a.png
│ ├── docker_pull.png
│ ├── docker_rm_id.png
│ ├── docker_stop.png
│ ├── all_containers.png
│ ├── docker_ps_demo.png
│ ├── docker_rmi_demo.png
│ ├── rel_info_alpine.png
│ ├── docker-run-alpine.png
│ ├── docker_images_demo.png
│ ├── docker_ps-a_stoped.png
│ ├── docker_ps_after_rm.png
│ ├── docker_ps_demo_1.png
│ ├── docker_run_redis.png
│ ├── docker_run_ubuntu.png
│ ├── docker_sleep_1000.png
│ ├── rotorocloud-webapp.png
│ ├── enter_inside_container.png
│ ├── docker_ps-a_ubuntu_exited.png
│ ├── docker_ps-a_ubuntu_status_up.png
│ ├── docker_ps_after_run_ubuntu.png
│ ├── rotorocloud-webapp_detached_mode.png
│ └── hostname_is_docker_id_of_container.png
├── 5_docker_run
│ ├── img
│ │ ├── logs.png
│ │ ├── stdin.png
│ │ ├── port_mapping.png
│ │ ├── additional_info.png
│ │ └── volume_mapping.png
│ └── docker_run.md
├── 2_presentation
│ └── dfbrel-0.0.pdf
├── 4_lab_env
│ └── labs_intro.md
├── 6_lab2
│ └── lab2.md
├── 7_docker_run_adv
│ └── docker_run_adv.md
├── 8_test
│ ├── test_intro.md
│ └── test.md
├── 3_demo_commands
│ └── demo_commands.md
└── 1_commands
│ └── 1commands_review.md
├── README.md
├── 7_registry
├── 7_1_docker_registry
│ ├── img
│ │ ├── image.png
│ │ ├── registry.png
│ │ ├── private_registry.png
│ │ └── private_registry_deploy.png
│ └── registry.md
├── 7_2_demo_registry_creation
│ └── demo6_registry.md
└── 7_3_docker_registry_test
│ └── test_registry.md
├── 3_docker_images
├── 3_1_docker_images
│ ├── img
│ │ ├── build.png
│ │ ├── errors.png
│ │ ├── layers.png
│ │ ├── dockerfile.png
│ │ ├── how_to_create_image.png
│ │ └── what_can_be_containerized.png
│ └── docker_images.md
├── 3_4_environment_variables
│ ├── img
│ │ ├── env_vars.png
│ │ ├── env_vars1.png
│ │ ├── docker_inspect.png
│ │ └── env_vars_in_docker.png
│ └── env_vars.md
├── 3_6_commands_and_entrypoint
│ ├── img
│ │ ├── command.png
│ │ ├── sleep_5.png
│ │ ├── entrypoint.png
│ │ ├── container_process.png
│ │ ├── container_process1.png
│ │ ├── os_inside_container.png
│ │ ├── os_inside_container1.png
│ │ └── commands_and_entrypoint.png
│ └── c_n_e.md
├── 3_3_demo_image_creation
│ └── demo.md
├── 3_5_lab4(env_vars)
│ └── lab4.md
├── 3_7_lab_commadns_entrypoints
│ └── lab5.md
├── 3_2_lab3
│ └── lab3.md
└── 3_8_test_images
│ └── test_images.md
├── 5_docker_storage
├── 5_1_docker_engine
│ ├── img
│ │ ├── engine.png
│ │ ├── cgroups.png
│ │ ├── namespace.PNG
│ │ └── containerization.png
│ └── engine.md
├── 5_3_docker_storage
│ ├── img
│ │ ├── volumes.png
│ │ ├── filesystem.png
│ │ ├── copy_on_write.png
│ │ ├── storage_drivers.png
│ │ ├── storage_layers.png
│ │ └── layered_architecture.png
│ └── docker_storage.md
├── 5_4_lab8
│ └── docker_storage.md
├── 5_5_docker_engine_test
│ └── test_engine.md
└── 5_2_lab7
│ └── lab7.md
├── 4_docker-compose
├── 4_1_docker-compose
│ ├── img
│ │ ├── voting_app.png
│ │ ├── docker_compose.png
│ │ ├── docker_compose1.png
│ │ ├── docker_compose_build.png
│ │ ├── voting_application.png
│ │ ├── voting_application1.png
│ │ ├── voting_application2.png
│ │ ├── docker_compose_commands.png
│ │ └── docker_compose_versions.png
│ └── docker-compose.md
├── 4_3_lab_docker_compose
│ └── lab6.md
└── 4_2_test_compose
│ └── test_compose.md
├── 6_network
├── 6_1_network_in_docker
│ ├── img
│ │ ├── embedded_dns.png
│ │ ├── user_networks.png
│ │ ├── default_networks.png
│ │ └── inspect_network.png
│ └── network_in_docker.md
├── 6_2_lab9
│ └── lab9_docker_networks.md
└── 6_3_docker_network_test
│ └── test_network.md
├── 8_container_orchestration
├── 8_3_kubernetes
│ ├── img
│ │ ├── claster.png
│ │ ├── kubectl.png
│ │ ├── master.png
│ │ ├── components.png
│ │ └── kubernetes.png
│ └── kubernetes.md
├── 8_2_docker_swarm
│ ├── img
│ │ ├── docker_swarm.png
│ │ ├── docker_swarm1.png
│ │ └── docker_service.png
│ └── docker_swarm.md
└── 8_1_orchestration
│ ├── img
│ ├── orchestration.png
│ ├── orchestration1.png
│ └── orchestration_technologies.png
│ └── orchestration.md
└── .gitignore
/9_YAML/img/yaml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/9_YAML/img/yaml.png
--------------------------------------------------------------------------------
/9_YAML/img/yaml1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/9_YAML/img/yaml1.png
--------------------------------------------------------------------------------
/9_YAML/img/yaml2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/9_YAML/img/yaml2.png
--------------------------------------------------------------------------------
/9_YAML/img/yaml_spaces.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/9_YAML/img/yaml_spaces.png
--------------------------------------------------------------------------------
/9_YAML/img/yaml_specials.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/9_YAML/img/yaml_specials.png
--------------------------------------------------------------------------------
/1_introduction/img/hi_alex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/1_introduction/img/hi_alex.png
--------------------------------------------------------------------------------
/9_YAML/img/data_types_yaml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/9_YAML/img/data_types_yaml.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps2.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_rm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_rm.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_rmi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_rmi.png
--------------------------------------------------------------------------------
/2_docker_commands/img/nginx_conf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/nginx_conf.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Docker-for-beginners-practical-experience
2 |
3 | ## Course sourse
4 |
5 | [Docker for beginners](https://stepik.org/course/123300/info)
6 |
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_attach.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_attach.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_exec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_exec.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_images.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_images.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps-a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps-a.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_pull.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_pull.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_rm_id.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_rm_id.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_stop.png
--------------------------------------------------------------------------------
/2_docker_commands/img/all_containers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/all_containers.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps_demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps_demo.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_rmi_demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_rmi_demo.png
--------------------------------------------------------------------------------
/2_docker_commands/img/rel_info_alpine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/rel_info_alpine.png
--------------------------------------------------------------------------------
/2_docker_commands/5_docker_run/img/logs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/5_docker_run/img/logs.png
--------------------------------------------------------------------------------
/2_docker_commands/5_docker_run/img/stdin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/5_docker_run/img/stdin.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker-run-alpine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker-run-alpine.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_images_demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_images_demo.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps-a_stoped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps-a_stoped.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps_after_rm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps_after_rm.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps_demo_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps_demo_1.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_run_redis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_run_redis.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_run_ubuntu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_run_ubuntu.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_sleep_1000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_sleep_1000.png
--------------------------------------------------------------------------------
/2_docker_commands/img/rotorocloud-webapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/rotorocloud-webapp.png
--------------------------------------------------------------------------------
/7_registry/7_1_docker_registry/img/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/7_registry/7_1_docker_registry/img/image.png
--------------------------------------------------------------------------------
/2_docker_commands/2_presentation/dfbrel-0.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/2_presentation/dfbrel-0.0.pdf
--------------------------------------------------------------------------------
/2_docker_commands/img/enter_inside_container.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/enter_inside_container.png
--------------------------------------------------------------------------------
/3_docker_images/3_1_docker_images/img/build.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_1_docker_images/img/build.png
--------------------------------------------------------------------------------
/3_docker_images/3_1_docker_images/img/errors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_1_docker_images/img/errors.png
--------------------------------------------------------------------------------
/3_docker_images/3_1_docker_images/img/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_1_docker_images/img/layers.png
--------------------------------------------------------------------------------
/5_docker_storage/5_1_docker_engine/img/engine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_1_docker_engine/img/engine.png
--------------------------------------------------------------------------------
/7_registry/7_1_docker_registry/img/registry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/7_registry/7_1_docker_registry/img/registry.png
--------------------------------------------------------------------------------
/2_docker_commands/5_docker_run/img/port_mapping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/5_docker_run/img/port_mapping.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps-a_ubuntu_exited.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps-a_ubuntu_exited.png
--------------------------------------------------------------------------------
/5_docker_storage/5_1_docker_engine/img/cgroups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_1_docker_engine/img/cgroups.png
--------------------------------------------------------------------------------
/5_docker_storage/5_3_docker_storage/img/volumes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_3_docker_storage/img/volumes.png
--------------------------------------------------------------------------------
/2_docker_commands/5_docker_run/img/additional_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/5_docker_run/img/additional_info.png
--------------------------------------------------------------------------------
/2_docker_commands/5_docker_run/img/volume_mapping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/5_docker_run/img/volume_mapping.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps-a_ubuntu_status_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps-a_ubuntu_status_up.png
--------------------------------------------------------------------------------
/2_docker_commands/img/docker_ps_after_run_ubuntu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/docker_ps_after_run_ubuntu.png
--------------------------------------------------------------------------------
/3_docker_images/3_1_docker_images/img/dockerfile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_1_docker_images/img/dockerfile.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/voting_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/voting_app.png
--------------------------------------------------------------------------------
/5_docker_storage/5_1_docker_engine/img/namespace.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_1_docker_engine/img/namespace.PNG
--------------------------------------------------------------------------------
/5_docker_storage/5_3_docker_storage/img/filesystem.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_3_docker_storage/img/filesystem.png
--------------------------------------------------------------------------------
/6_network/6_1_network_in_docker/img/embedded_dns.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/6_network/6_1_network_in_docker/img/embedded_dns.png
--------------------------------------------------------------------------------
/6_network/6_1_network_in_docker/img/user_networks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/6_network/6_1_network_in_docker/img/user_networks.png
--------------------------------------------------------------------------------
/6_network/6_1_network_in_docker/img/default_networks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/6_network/6_1_network_in_docker/img/default_networks.png
--------------------------------------------------------------------------------
/6_network/6_1_network_in_docker/img/inspect_network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/6_network/6_1_network_in_docker/img/inspect_network.png
--------------------------------------------------------------------------------
/7_registry/7_1_docker_registry/img/private_registry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/7_registry/7_1_docker_registry/img/private_registry.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_3_kubernetes/img/claster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_3_kubernetes/img/claster.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_3_kubernetes/img/kubectl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_3_kubernetes/img/kubectl.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_3_kubernetes/img/master.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_3_kubernetes/img/master.png
--------------------------------------------------------------------------------
/2_docker_commands/img/rotorocloud-webapp_detached_mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/rotorocloud-webapp_detached_mode.png
--------------------------------------------------------------------------------
/3_docker_images/3_4_environment_variables/img/env_vars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_4_environment_variables/img/env_vars.png
--------------------------------------------------------------------------------
/3_docker_images/3_4_environment_variables/img/env_vars1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_4_environment_variables/img/env_vars1.png
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/img/command.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_6_commands_and_entrypoint/img/command.png
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/img/sleep_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_6_commands_and_entrypoint/img/sleep_5.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/docker_compose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/docker_compose.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/docker_compose1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/docker_compose1.png
--------------------------------------------------------------------------------
/5_docker_storage/5_1_docker_engine/img/containerization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_1_docker_engine/img/containerization.png
--------------------------------------------------------------------------------
/5_docker_storage/5_3_docker_storage/img/copy_on_write.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_3_docker_storage/img/copy_on_write.png
--------------------------------------------------------------------------------
/5_docker_storage/5_3_docker_storage/img/storage_drivers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_3_docker_storage/img/storage_drivers.png
--------------------------------------------------------------------------------
/5_docker_storage/5_3_docker_storage/img/storage_layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_3_docker_storage/img/storage_layers.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_3_kubernetes/img/components.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_3_kubernetes/img/components.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_3_kubernetes/img/kubernetes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_3_kubernetes/img/kubernetes.png
--------------------------------------------------------------------------------
/2_docker_commands/img/hostname_is_docker_id_of_container.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/2_docker_commands/img/hostname_is_docker_id_of_container.png
--------------------------------------------------------------------------------
/3_docker_images/3_1_docker_images/img/how_to_create_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_1_docker_images/img/how_to_create_image.png
--------------------------------------------------------------------------------
/3_docker_images/3_4_environment_variables/img/docker_inspect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_4_environment_variables/img/docker_inspect.png
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/img/entrypoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_6_commands_and_entrypoint/img/entrypoint.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/docker_compose_build.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/docker_compose_build.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/voting_application.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/voting_application.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/voting_application1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/voting_application1.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/voting_application2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/voting_application2.png
--------------------------------------------------------------------------------
/5_docker_storage/5_3_docker_storage/img/layered_architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/5_docker_storage/5_3_docker_storage/img/layered_architecture.png
--------------------------------------------------------------------------------
/7_registry/7_1_docker_registry/img/private_registry_deploy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/7_registry/7_1_docker_registry/img/private_registry_deploy.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_2_docker_swarm/img/docker_swarm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_2_docker_swarm/img/docker_swarm.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_2_docker_swarm/img/docker_swarm1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_2_docker_swarm/img/docker_swarm1.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_1_orchestration/img/orchestration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_1_orchestration/img/orchestration.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_1_orchestration/img/orchestration1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_1_orchestration/img/orchestration1.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_2_docker_swarm/img/docker_service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_2_docker_swarm/img/docker_service.png
--------------------------------------------------------------------------------
/3_docker_images/3_1_docker_images/img/what_can_be_containerized.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_1_docker_images/img/what_can_be_containerized.png
--------------------------------------------------------------------------------
/3_docker_images/3_4_environment_variables/img/env_vars_in_docker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_4_environment_variables/img/env_vars_in_docker.png
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/img/container_process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_6_commands_and_entrypoint/img/container_process.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/docker_compose_commands.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/docker_compose_commands.png
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/img/docker_compose_versions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/4_docker-compose/4_1_docker-compose/img/docker_compose_versions.png
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/img/container_process1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_6_commands_and_entrypoint/img/container_process1.png
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/img/os_inside_container.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_6_commands_and_entrypoint/img/os_inside_container.png
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/img/os_inside_container1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_6_commands_and_entrypoint/img/os_inside_container1.png
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/img/commands_and_entrypoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/3_docker_images/3_6_commands_and_entrypoint/img/commands_and_entrypoint.png
--------------------------------------------------------------------------------
/8_container_orchestration/8_1_orchestration/img/orchestration_technologies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lexxx42/Docker-for-beginners-practical-experience/HEAD/8_container_orchestration/8_1_orchestration/img/orchestration_technologies.png
--------------------------------------------------------------------------------
/7_registry/7_2_demo_registry_creation/demo6_registry.md:
--------------------------------------------------------------------------------
1 | # Работа со своим часным registry и registry от google
2 |
3 | Тут все настолько сложно, что у меня мозг закипел.
4 |
5 | Видео ускорено. Сложные моменты не объяснены. Показан не весь флоу, а часть с середины.
6 |
7 | Скорее всего, видео сделано для демонстрации возможностей, без погружения в детали.
8 |
--------------------------------------------------------------------------------
/2_docker_commands/4_lab_env/labs_intro.md:
--------------------------------------------------------------------------------
1 | # Лабораторные работы
2 |
3 | Чтобы узнать версию докера на хосте
4 |
5 | ```docker
6 | docker version
7 | ```
8 |
9 | Чтобы остановить + начало id
10 |
11 | ```docker
12 | docker stop 5a
13 | ```
14 |
15 | Удалить все остановленные
16 |
17 | ```docker
18 | docker stop $(docker ps -aq)
19 | ```
20 |
21 | Запустить образ, указав имя образа
22 |
23 | ```docker
24 | docker run --name webapp nginx:1.14-alpine
25 | ```
26 |
27 | Удалить все образы находящиеся локально на хосте + первые символы id
28 |
29 | ```docker
30 | docker rmi 98 62 1b
31 | ```
32 |
33 | ```docker
34 | docker rmi -f $(docker images)
35 | ```
36 |
--------------------------------------------------------------------------------
/2_docker_commands/6_lab2/lab2.md:
--------------------------------------------------------------------------------
1 | # lab 2
2 |
3 | ## Вначале давай исследуем окружение. Сколько контейнеров запущено на хосте?
4 |
5 | ```docker
6 | docker ps
7 | ```
8 |
9 | ## Запусти контейнер rotorocloud/simple-webapp-rockets с тегом v2, соспоставь порт 8080 контейнера к порту 30123 хоста.
10 |
11 | ```docker
12 | docker run -p 30123:8080 rotorocloud/simple-webapp-rockets:v2
13 | ```
14 |
15 | ## next
16 |
17 | Мы ошиблись при запуске контейнера webportal, его внешний порт должен быть 30500.
18 | Исправь это. Не забудь назвать его webportal.
19 |
20 | Посмотри информацию о старом контейнере.
21 | Порты невозможно переопределить на запущенном контейнере.
22 |
23 | ```docker
24 | docker run -p 30500:80 --name webportal nginx:alpine
25 | ```
26 |
--------------------------------------------------------------------------------
/3_docker_images/3_3_demo_image_creation/demo.md:
--------------------------------------------------------------------------------
1 | + Добавить тег созданному образу докера
2 |
3 | ```docker
4 | docker tag [id_container] [name]:[tag]
5 | ```
6 |
7 | + Отправить образ в хранилище
8 |
9 | ```docker
10 | docker push [name]:[tag]
11 | ```
12 |
13 | + Нужно залогиниться в хранилище, чтобы туда пушить
14 |
15 | ```docker
16 | docker login
17 | ```
18 |
19 | Username, Password
20 | [Запушил свой репозиторий](https://hub.docker.com/r/alex42konukhov/yandex-weather-bot)
21 |
22 | > Make sure you have tagged your image in this format:
23 | > {{username}}/{{imagename}}:{{version}}
24 | > And push with
25 | > [link](https://forums.docker.com/t/docker-push-error-requested-access-to-the-resource-is-denied/64468/10)
26 |
27 | ```docker
28 | docker tag yandex-weather-bot:debian-bullseye alex42konukhov/yandex-weather-bot:debian-bullseye
29 | ```
30 |
31 | ```docker
32 | docker push alex42konukhov/yandex-weather-bot:debian-bullseye
33 | ```
34 |
35 | Чтобы спуллить репозиторий:
36 |
37 | ```docker
38 | docker pull alex42konukhov/yandex-weather-bot:debian-bullseye
39 | ```
40 |
--------------------------------------------------------------------------------
/2_docker_commands/7_docker_run_adv/docker_run_adv.md:
--------------------------------------------------------------------------------
1 | # Как получить доступ извне хоста?
2 |
3 | ```shell
4 | ip addr
5 | ```
6 |
7 | `enp0s3` - внешний адрес докер хоста.
8 |
9 | ## Проблема
10 |
11 | Не могу один вопрос решить. "Offline. This Jenkins instance appears to be offline."
12 |
13 | 1. Использую команду из https://github.com/jenkinsci/docker/blob/master/README.md
14 | docker run -d -v jenkins_home:/var/jenkins_home -p 8080:8080 -p 50000:50000 --restart=on-failure jenkins/jenkins:
15 | lts-jdk11
16 | 2. Чекаю id контейнера
17 | docker ps
18 | 3. Распечатываю пароль
19 | docker exec cfa cat /var/jenkins_home/secrets/initialAdminPassword
20 | 4. Ввожу пароль в форму
21 | 5. Jenkins оффлайн
22 | 6. Чекаю
23 | stackoverflow: https://stackoverflow.com/questions/42408703/why-does-jenkins-say-this-jenkins-instance-appears-to-be-offline
24 | 7. Пишут, что надо отредактировать UpdateCenter.xml
25 | Вопрос: как это сделать у экземпляра (или контейнера, не знаю как правильно)?
26 | Может другое решение есть? У меня пока не получается...
27 | Хост Windows 11 Pro Version 21H2
28 | Виртуальная машина с докером: Ubuntu 22.04.2 LTS 64 bit
29 | Проброшен порт: хост 8022, гость 22. Подключаюсь через SSH
30 | Доступ к интернету на машине есть.
31 |
--------------------------------------------------------------------------------
/1_introduction/2how_to_begin_to_wrork_with_docker.md:
--------------------------------------------------------------------------------
1 | # Как начать работу с Docker
2 |
3 | В данный момент у докера есть два варианта использования community edition и enterprise edition.
4 |
5 | Первый - это набор бесплатных продуктов. Второй - сертифицированная и поддерживаемая контейнерная платформа для
6 | предприятия, которая включает в себя расширения по управлению хранением, безопасностью и оркестрацией. Она стоит денег.
7 |
8 | Решение по оркестрации контейнеров есть не только у докера, мы об этом поговорим позже в этом курсе.
9 |
10 | В этом курсе мы будем работать с community edition. Эта редакция доступна на Линукс, маке и Виндовс, также доступна на
11 | облачных решениях. В демо мы посмотрим, как установить и начать работать с докер на машине с Линукс.
12 |
13 | Если ты на маке или Виндовс есть два варианта:
14 |
15 | 1. установить виртуальную машину с Линукс при помощь virtualbox или какой-то другой платформы виртуализации, а потом
16 | выполнить шаги из демо, которые идут после лекции. На мой взгляд, - это самый простой вариант начать работать с
17 | докером.
18 | 2. установить докер десктоп для мака или Виндовс в соответствии с твоей системой.
19 |
20 | О различиях докера для мака и Виндовс я расскажу в конце курса, так что, если ты выбрал второй путь, посмотри нужный
21 | раздел.
22 |
23 | Теперь давай перейдем в демо, где мы посмотрим как установить докер на Линукс.
24 |
--------------------------------------------------------------------------------
/2_docker_commands/8_test/test_intro.md:
--------------------------------------------------------------------------------
1 | # Тест: команды
2 |
3 | Остановись на минутку и прочитай до конца.
4 |
5 | Для получения сертификата Stepik придется пройти несколько тестов. Они будут не только по материалам лекций и тебе
6 | что-то придется погуглить.
7 |
8 | Изначально разделов с тестами не было в курсе, и поэтому в них я забегаю немного вперед в некоторых темах. Также для
9 | новичка вопросы могут показаться сложными, поскольку я взял из заготовок своего курса по продвинутому Docker.
10 |
11 | Пожалуйста, не обижайся на этот момент и не ставь курсу минусов. Не относись к этому очень серьезно - эти тесты можно
12 | пройти просто методом тыка или просто пропустить. Но я надеюсь, что после них тебе захочется еще больше погрузиться в
13 | технологию.
14 |
15 | Опять же, ты всегда сможешь к ним вернуться, когда завершишь программу, а приятным бонусом к бесплатному курсу будет
16 | сертификат, который без тестов Stepik не выдает.
17 |
18 | Еще момент. Эти тесты добавлены 11.11.2022. Поэтому здесь могут быть небольшие опечатки или ошибки. Если ты их заметишь,
19 | пожалуйста напиши в нашу группу в Телеграм или мне в личку @dushasokol.
20 |
21 | Вот полезные ссылки для прохождения теста:
22 |
23 | https://docs.docker.com/engine/reference/commandline/container/
24 |
25 | https://docs.docker.com/engine/reference/run/
26 |
27 | https://docs.docker.com/engine/reference/commandline/system/
28 |
--------------------------------------------------------------------------------
/6_network/6_2_lab9/lab9_docker_networks.md:
--------------------------------------------------------------------------------
1 | # Лабораторная №9 (Docker Networks)
2 |
3 | 1. Исследуй текущее окружение Docker и определи, какое количество networks присутствует в системе
4 |
5 | ```shell
6 | docker network ls
7 | ```
8 |
9 | 2. Какой ID соответствует мостовой сети (bridge network)?
10 |
11 | ```shell
12 | docker network ls
13 | ```
14 |
15 | 3. Мы только что запустили контейнер с названием alpine-1. Определи к какой сети он присоединен.
16 |
17 | ```shell
18 | docker inspect alpine-1
19 | ```
20 |
21 | 4. Какая подсеть сконфигурирована в сети bridge?
22 |
23 | ```shell
24 | docker network inspect bridge
25 | ```
26 |
27 | 5. Запусти контейнер с названием alpine-2 с помощью образа alpine и прикрепи его к сети none.
28 |
29 | ```shell
30 | docker run -d --name alpine-2 --network=none alpine sleep 100
31 | ```
32 |
33 | 6. Создай новую сеть с названием wp-mysql-network, которая будет использовать сетевой драйвер bridge. Назначь ей
34 | 172.22.0.0/24 подсеть. Настрой Gateway 172.22.0.1
35 |
36 | ```shell
37 | docker network create --driver bridge --subnet 172.22.0.0/24 --gateway 172.22.0.1 wp-mysql-network
38 | ```
39 |
40 | 7. Разверни базу mysql с помощью образа mysql. Контейнер должен называться mysql-db. Прикрепи его к только что созданной
41 | сети wp-mysql-network
42 | Установи пароль для использования базы данных db_pass123. Переменная окружения, ответственная за это
43 | MYSQL_ROOT_PASSWORD
44 |
45 | ```shell
46 | docker run -d -e MYSQL_ROOT_PASSWORD=db_pass123 --name mysql-db --network wp-mysql-network mysql
47 | ```
48 |
49 | 8. Разверни веб-приложение с названием webapp, используй образ rotorocloud/webapp-mysql. Выставь (Expose) порт 30080 на
50 | хост. Приложение использует переменную окружения DB_Host в качестве имени хоста базы данных mysql. Убедись, что
51 | прикрепил вновь созданную сеть wp-mysql-network
52 |
53 | ```shell
54 | docker run --network=wp-mysql-network -e DB_Host=mysql-db -e DB_Password=db_pass123 -p 30080:8080 --name webapp -d rotorocloud/webapp-mysql
55 | ```
56 |
--------------------------------------------------------------------------------
/3_docker_images/3_5_lab4(env_vars)/lab4.md:
--------------------------------------------------------------------------------
1 | # Лабораторная №4 (EnvVars)
2 |
3 | 1. Исследуй переменные окружения в запущенном контейнере и определи значение переменной ROCKET_SIZE
4 |
5 | ```docker
6 | docker ps
7 | ```
8 |
9 | ```docker
10 | docker inspect 34ce4f2a7b25
11 | ```
12 |
13 | 2. Запусти контейнер с именем rocket-app из образа rotorocloud/simple-webapp-rockets и установи переменную ROCKET_SIZE в
14 | значение big. Сделай приложение доступным на порту 30888 докер-хоста. Приложение в контейнере работает на 8080 порту.
15 |
16 | ```docker
17 | docker run -d -p 30888:8080 -e ROCKET_SIZE=big --name rocket-app rotorocloud/simple-webapp-rockets
18 | ```
19 |
20 | 3. Разверни экземпляр базы mysql с помощью образа mysql и назови контейнер mysql-db.
21 |
22 | Для этого контейнера установи пароль db_pass123. Ты можешь посмотреть правильный образ mysql на Docker Hub и там же
23 | узнать, как правильно проинициализировать root-пароль для ее контейнеризированной версии.
24 |
25 | ```docker
26 | docker run --name mysql-db -e MYSQL_ROOT_PASSWORD=db_pass123 -d mysql:latest
27 | ```
28 |
29 | 4. Узнай, сколько баз данных создано в контейнере с mysql
30 |
31 | ```docker
32 | docker ps
33 | ```
34 |
35 | Connect to the MySQL server running inside the container:
36 |
37 | ```docker
38 | docker exec -it fd42ad81b5d7 mysql -p
39 | ```
40 |
41 | Enter the MySQL root password you specified when starting the container:
42 |
43 | ```
44 | db_pass123
45 | ```
46 |
47 | Run the following SQL command to list all databases:
48 |
49 | ```sql
50 | SHOW DATABASES;
51 | ```
52 |
53 | 5. Попробуй cнова обратиться к базе и посмотри текущее значение переменной окружения MYSQL_ROOT_PASSWORD.
54 | ИНФО: Мы что-то изменили, детально исследуй контейнер
55 |
56 | ```sql
57 | EXIT;
58 | ```
59 |
60 | ```docker
61 | docker ps
62 | ```
63 |
64 | ```docker
65 | docker inspect
66 | ```
67 |
68 | 6. Все верно, мы поменяли пароль в базе, но переменная осталась прежняя. Снова узнай, сколько баз данных создано в
69 | контейнере с mysql.
70 | ИНФО: Новый пароль db_newpass123.
71 |
72 | ```docker
73 | docker exec -it fd42ad81b5d7 mysql -p
74 | ```
75 |
76 | ```
77 | db_newpass123
78 | ```
79 |
80 | ```sql
81 | SHOW DATABASES;
82 | ```
83 |
--------------------------------------------------------------------------------
/5_docker_storage/5_4_lab8/docker_storage.md:
--------------------------------------------------------------------------------
1 | # Лабораторная №8 (Docker Storage)
2 |
3 | 1. В каком месте находятся файлы, связанные с докер-контейнерами и докер-образами?
4 |
5 | `/var/lib/docker`
6 |
7 | 2. В какой папке внутри директории /var/lib/docker/containers лежат файлы связанные с образом, от которого запущен
8 | контейнер alpine-3?
9 |
10 | ```shell
11 | docker ps -a
12 | ```
13 |
14 | ```shell
15 | docker inspect
16 | ```
17 |
18 | 3. Запусти контейнер с mysql и дай ему имя mysql-db (используй образ mysql). Установи ROOT-пароль к базе данных в
19 | db_pass123
20 | ИНФО Запусти это в detached mode.
21 |
22 | ```shell
23 | docker run -d --name mysql-db -e MYSQL_ROOT_PASSWORD=db_pass123 mysql
24 | ```
25 |
26 | 4. Мы только что записали данные в базу mysql. Чтобы просмотреть содержимое воспользуйся скриптом get-data.sh, он
27 | доступен в директории /home/moon. Сколько клиентских записей присутствует в базе?
28 | Запусти: sh /home/moon/get-data.sh
29 |
30 | ```shell
31 | sh /home/moon/get-data.sh
32 | ```
33 |
34 | 5. База данных сломалась. Ты можешь просмотреть данные сейчас?
35 | Попробуй посмотреть данные той же командой. Попробуй найти контейнер.
36 |
37 | ```shell
38 | docker ps -a
39 | ```
40 |
41 | 6. Запусти mysql-контейнер снова, но в этот раз подключи том (volume) к контейнеру. В томе данные будут на постоянном
42 | хранении по размещению /opt/data хоста.
43 | Используй тоже самое имя: mysql-db и тот же пароль: db_pass123, как и ранее. Mysql хранит данные в /var/lib/mysql
44 | внутри контейнера.
45 |
46 | ```shell
47 | docker run -d --name mysql-db -e MYSQL_ROOT_PASSWORD=db_pass123 -v /opt/data:/var/lib/mysql mysql
48 | ```
49 |
50 | 7. Мы только что снова записали данные в базу. Запусти скрипт get-data.sh, чтобы убедиться, что они на месте.
51 | Запусти: `sh /home/moon/get-data.sh`
52 |
53 | 8. У нас снова падение! Все контейнеры снова уничтожены. Но теперь все наши данные хранятся в директории /opt/data.
54 | Разверни БД в новом экземпляре mysql, используя те же параметры.
55 | Просто запусти предыдущую команду для запуска контейнера. Можешь взять ее отсюда:
56 |
57 | ```shell
58 | docker run -v /opt/data:/var/lib/mysql -d --name mysql-db -e MYSQL_ROOT_PASSWORD=db_pass123 mysql
59 | ```
60 |
61 | 9. Сравни данные и убедись, что все на месте.
62 | Запусти: `sh /home/moon/get-data.sh`
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/3_docker_images/3_4_environment_variables/env_vars.md:
--------------------------------------------------------------------------------
1 | # Привет, в этой лекции мы поговорим о переменных окружения.
2 |
3 |
4 |
5 | Начнем с нашего простого приложения, показывающее ракеты. Оно написано на python. Взгляни на
6 | этот участок кода. Он создает веб-сервер, который демонстрирует веб-страницу с ракетой. Если ты
7 | посмотришь внимательно, ты найдешь строку, которая определяет размер ракеты как small.
8 |
9 | В данный момент все это работает прекрасно. Однако, если ты решишь изменить размер ракеты в
10 | будущем, то придется менять код приложения. Лучшая практика в таком случае вынести
11 | информацию из кода приложения в переменную окружения с именем ROCKET_SIZE.
12 |
13 |
14 |
15 | Внесем изменения в код. Теперь при запуске приложения установим переменную окружения
16 | ROCKET_SIZE в желаемое значение при помощи команды `export ROCKET_SIZE=big; python3 app.py` и
17 | запустим приложение. Как видишь такой подход может избавить нас от сборки отдельного билда
18 | приложения под каждый размер ракеты.
19 |
20 |
21 |
22 | Пересоберем образ и запустим: `docker run rotorocloud/simple-webapp-rockets`
23 |
24 | Приложение покажет нам ракету размера small. Совсем не то, что ожидали. Это потому, что мы
25 | назначили переменную окружения в нашей хостовой среде, но внутри контейнера ее не существует.
26 | Для того, чтобы установить эту переменную в контейнере используй параметр -e при запуске.
27 | В нашем случае: `docker run -e ROCKET_SIZE=big rotorocloud/simple-webapp-rockets`
28 | С этой опцией ты можешь запустить много одинаковых контейнеров, которые будут
29 | демонстрировать разные ракеты. Просто назначь разные переменные окружения этим
30 | контейнерам при старте.
31 |
32 |
33 |
34 | Как узнать, какие переменные существуют в уже запущенном контейнере и какие у них значения?
35 |
36 | С помощью команды `docker inspect`. Эта команда показывает развернутую информацию о
37 | работающем контейнере, в том числе в секции config ты найдешь список всех переменных
38 | окружения этого контейнера.
39 |
40 | Это все в этой короткой лекции, переходим к практике.
41 |
42 | установить переменную окружения внутри контейнера
43 | ```docker
44 | docker run -e
45 | ```
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
--------------------------------------------------------------------------------
/6_network/6_3_docker_network_test/test_network.md:
--------------------------------------------------------------------------------
1 | # Тест: Docker Network
2 |
3 | Концепция сети в плоскостях виртуализации/контейнеризации оставила от классических сетей общие принципы построения, но
4 | внесла свое новое видение предмета. Я говорю о таких вещах, как виды сетей в VM и network namespaces.
5 |
6 | Из-за этих вещей иногда классическому сетевому админу бывает сложно погрузиться в мир devops. На моем ресурсе
7 | rotoro.cloud в курсе Certified Kubernetes Administrator мы обсуждаем эти нюансы, поэтому, если у тебя там есть подписка,
8 | можешь проверить.
9 |
10 | Ок, чтобы не усложнять я не лез в оверлейные сети, но в любом случае тебе что-то придется искать в документации.
11 |
12 | Еще раз упомяну - эти тесты сложнее материала для новичков и требуются, только если ты хочешь сертификат об окончании.
13 | Если тебя это задевает и ты считаешь, что курс стал от них хуже - просто пропусти эти тесты.
14 |
15 | Вот полезные ссылки:
16 |
17 | https://docs.docker.com/network/
18 |
19 | https://docs.docker.com/network/bridge/
20 |
21 | https://docs.docker.com/engine/reference/commandline/network/
22 |
23 | https://docs.docker.com/engine/tutorials/networkingcontainers/
24 |
25 | 1. Как получить список доступных по умолчанию сетей в Docker?
26 |
27 | > docker network ls
28 |
29 | 2. Какой командой можно посмотреть настройки сети и назначенный IP-адрес контейнера с id 7206cfc5e8ae и образом redis?
30 |
31 | > docker inspect 7206cfc5e8ae
32 |
33 | 3. Какой сетевой драйвер будет использован по умолчанию, если ты не указал его явно?
34 |
35 | > bridge
36 |
37 | 4. Какой тип сети следует выбрать, чтобы сетевой стек контейнера не был изолирован от хоста, а использовал его сетевое
38 | пространство, а также чтобы у контейнера не было бы своего собственного IP-адреса?
39 |
40 | > host
41 |
42 | 5. Как узнать подсеть и шлюз сети 3afa2bbcfce8?
43 |
44 | > docker network inspect 3afa2bbcfce8
45 | > docker inspect 3afa2bbcfce8
46 |
47 | 6. Что из приведенных команд создаст пользовательскую мостовую сеть с названием stage-ns? (Выбери 3)
48 |
49 | > docker network create --driver bridge stage-ns
50 | > docker network create -d bridge stage-ns
51 | > docker network create stage-ns
52 |
53 | 7. Какая команда подключит работающий контейнер с именем feature к существующей мостовой сети stage-ns?
54 |
55 | > docker network connect stage-ns feature
56 |
57 | 8. Какая команда отключит работающий контейнер с именем feature от мостовой сети stage-ns?
58 |
59 | > docker network disconnect stage-ns feature
60 |
61 | 9. Как можно удалить все неиспользуемые сети?
62 |
63 | > docker network prune
64 |
65 | 10. Как удалить сеть stage-ns?
66 |
67 | > docker network rm stage-ns
68 |
--------------------------------------------------------------------------------
/1_introduction/3demo_how_to_install_docker_on_linux.md:
--------------------------------------------------------------------------------
1 | # Установка и настройка Docker
2 |
3 | Первое требование - это определиться с физической или виртуальной машиной, где будет стоять докер.
4 |
5 | На этой машине тебе понадобиться подходящая ОС, в моем случае я поставлю Убунту 18.04 на виртульную машину от
6 | виртуалбокса, зупущенную поверх Виндовс 7.
7 |
8 | Таким образом, я буду выполнять установку Docker на Убунту.
9 |
10 | Я буду устанавливать на Windows 11.
11 |
12 | [Ubuntu 22.04.2 LTS](https://ubuntu.com/download/desktop)
13 |
14 | [VirtualBox 7.0.6](https://www.virtualbox.org/wiki/Downloads)
15 |
16 | Идем на страницу с документацией
17 |
18 | [docker docs](https://docs.docker.com/)
19 |
20 | В раздел download and install.
21 |
22 | В этом разделе размещены подробные мануалы о том, как поставить докер комьюнити едишн на разные платформы.
23 |
24 | Все что касается ентерпрайз едишн теперь в ведении мирантис после того, как они купили команду кодер интерпрайз.
25 |
26 | Таким образом докер (неразборчиво "бот"?) бесплатный для нас, но не всегда. Со второго ноября 2020г появились
27 | ограничения для бесплтного размещения своих образов. Посмотри тарифные планы, если хочешь узнать больше.
28 |
29 | Тем временем я выбрал свою платформу, у меня это Линукс. Промотал до Убунту 64 бита.
30 |
31 | Предварительные требования гласят, что на 18.04 можно установить докер.
32 |
33 | Я перейду в свой терминал и командой
34 |
35 | ```bash
36 | cat /etc/*rel*
37 | ```
38 |
39 | На момент 16.03.2022 установка докера отличается от установки на видео.
40 |
41 | Стоит всегда следовать актуальному флоу с официальной документации
42 |
43 | [docker docs](https://docs.docker.com/desktop/install/ubuntu/)
44 |
45 | Установка завершена, давай что-нибудь запустим.
46 |
47 | Переходим на сайт
48 |
49 | [hub.docker](https://hub.docker.com/)
50 |
51 | На нем ты найдешь много известных и популярных докерезированных продуктов, таких как nginx, mongodb и др.
52 |
53 | Я ищу образ приложения whalesay, копирую команду
54 |
55 | ```bash
56 | sudo docker run docker/whalesay cowsay Hi, Alex!
57 | ```
58 |
59 | С этой командой докер в репозиторий, скачает нужный образ и запустит его на хосте с указанными мной параметрами, а
60 | именно приветствием Hi, Alex!
61 |
62 | Хочу напомнить, что в этом курсе тебе не обязательно устанавливать и настраивать свое ПО, как я говорил в лекции, мы
63 | предоставим тебе возможность практиковаться прямо из браузера в рамках наших лабораторных.
64 |
65 | Также у тебя всегда будет возможность практиковаться в песочнице, о который я тоже рассказывал в лекции.
66 |
67 | Но я буду только рад, если ты повторишь мои шаги и попрактикуешься - это пойдет только на пользу.
68 |
69 | А тем временем кит сказал "Hi, Alex!", замечательно! У нас все получилось (:
70 |
71 |
72 |
--------------------------------------------------------------------------------
/4_docker-compose/4_3_lab_docker_compose/lab6.md:
--------------------------------------------------------------------------------
1 | # Лабораторная №6 (Docker Compose)
2 |
3 | 1. Создай экземпляр базы данных postgres в контейнере с названием db, образ postgres, переменные окружения
4 | POSTGRES_PASSWORD=mysecretpassword
5 |
6 | Если ты не уверен в правильности, посмотри в подсказке.
7 |
8 | ```docker
9 | docker run --name db -e POSTGRES_PASSWORD=mysecretpassword -d postgres
10 | ```
11 |
12 | 2. Теперь создай простой контейнер с wordpress, он должен называться wordpress, образ: wordpress, сделай link этому
13 | контейнеру к контейнеру с именем db выставь 30085 порт на докер-хост
14 |
15 | Если ты не уверен в правильности, посмотри в подсказке.
16 |
17 | ```docker
18 | docker run -d --name wordpress -p 30085:80 --link db:db wordpress
19 | ```
20 |
21 | 3. Сейчас у нас уже развернут рабочий сайт на wordpress, ты можешь посмотреть на него через вкладку в терминале. Давай
22 | теперь сделаем это с помощью Docker Compose!
23 |
24 | Если ты видишь ответ Страница недоступна, поменяй в URL протокол на https
25 |
26 | Сначала надо прибрать за собой, давай удалим все, что осталось от предыдущих шагов.
27 |
28 | Удали все контейнеры - db и wordpress
29 |
30 | ``docker
31 | docker ps -a
32 | ``
33 |
34 | ```docker
35 | docker stop
36 | ```
37 |
38 | ```docker
39 | docker rm
40 | ```
41 |
42 | 4. Создай файл docker-compose.yml в размещении /root/wordpress. Обрати внимание, размещение должно быть
43 | /root/wordpress/docker-compose.yml, иначе система не сможет правильно проверить результат. Сделай sudo -i, пароль
44 | selena. После этого запусти стек с помощью docker-compose в detached mode.
45 |
46 | Важно, чтобы в файле спецификация была такой же, как и раньше, т.е. контейнеры были wordpress и db и не забудь прокинуть
47 | нужные порты
48 |
49 | ```shell
50 | sudo su
51 | ```
52 |
53 | ```shell
54 | cd /root/wordpress
55 | ```
56 |
57 | ```shell
58 | touch docker-compose.yml
59 | ```
60 |
61 | ```shell
62 | nano docker-compose.yml
63 | ```
64 |
65 | 5.
66 |
67 | ```
68 | docker-compose.yaml:
69 |
70 | version: "3"
71 | services:
72 | wordpress:
73 | image: wordpress
74 | ports:
75 | - "30085:80"
76 | links:
77 | - db
78 | db:
79 | image: postgres
80 | environment:
81 | - POSTGRES_PASSWORD=mysecretpassword
82 | ```
83 |
84 | ```docker
85 | docker-compose up -d
86 | ```
87 |
88 | 6. Мы что-то поменяли, сколько реплик контейнеров в службе wordpress?
89 |
90 | ```docker
91 | docker-compose ps
92 | ```
93 |
94 | 7. Увеличь количество реплик wordpress до 2.
95 |
96 | ```docker
97 | docker-compose up -d --scale wordpress=2
98 | ```
99 |
100 | ```docker
101 | docker-compose ps
102 | ```
103 |
104 | 8. Останови стек docker-compose.
105 | Убедись, что Docker Compose корректно положил стек
106 |
107 | ```docker
108 | docker-compose down
109 | ```
110 |
111 | ```docker
112 | docker-compose ps
113 | ```
114 |
--------------------------------------------------------------------------------
/5_docker_storage/5_5_docker_engine_test/test_engine.md:
--------------------------------------------------------------------------------
1 | # Тест: Docker Engine
2 |
3 | Тема движка Docker одна из самых сложных, вот за ней и скрывается 'магия' контейнеризации.
4 |
5 | В курсе для новичков я не ставил целью объяснить, как это работает в глубине, а лишь дать обзор темы. Как обычно вопросы
6 | немного сложнее материала лекции.
7 |
8 | Еще раз упомяну - эти тесты сложнее материала для новичков и требуются, только если ты хочешь сертификат об окончании.
9 | Если тебя это задевает и ты считаешь, что курс стал от них хуже - просто пропусти эти тесты.
10 |
11 | Вот полезные ссылки:
12 |
13 | https://docs.docker.com/get-started/overview/
14 |
15 | https://docs.docker.com/engine/
16 |
17 | https://docs.docker.com/storage/
18 |
19 | https://docs.docker.com/engine/reference/commandline/volume/#child-commands
20 |
21 | 1. Какие компоненты входят в Docker Engine?
22 |
23 | > Docker Cli, Docker Daemon, REST API
24 |
25 | 2. Какой компонент Docker управляет образами, контейнерами, томами и сетями?
26 |
27 | > Docker Daemon
28 |
29 | 3. Какой компонент по умолчанию отвечает за управление контейнерами в современных поставках Docker в Linux?
30 |
31 | > LibContainer
32 |
33 | 4. Можем ли запускать контейнеры без установки Docker?
34 |
35 | > Да (kubernetis для запуска контейнеров из docker образов "начинает использовать" cri-o вместо docker)
36 |
37 | 5. Какой компонент отвечает за поддержание контейнеров в живом состоянии, когда Docker Daemon отключается?
38 |
39 | > Containerd-Shim
40 |
41 | 6. Какими объектами управляет Docker Engine?
42 |
43 | > Networks, Volumes, Images, Containers
44 |
45 | 7. Данные внутри контейнера по умолчанию являются постоянными?
46 |
47 | > Нет
48 |
49 | 8. Какая из этих сущностей используется только для чтения и является шаблоном для создания контейнеров?
50 |
51 | > Docker images
52 |
53 | 9. Где по умолчанию Docker хранит свои данные?
54 |
55 | > /var/lib/docker
56 |
57 | 10. Какая команда покажет версию Docker Engine?
58 |
59 | > docker version
60 |
61 | 11. По умолчанию все файлы внутри контейнера находятся в записываемом слое контейнера?
62 |
63 | > Да
64 |
65 | 12. Тома (Volumes) являются предпочтительным механизмом для организации постоянного хранения для докер-контейнеров?
66 |
67 | > Да
68 |
69 | 13. Какой командой мы можем удалить неиспользуемые тома?
70 |
71 | > docker volume prune
72 |
73 | 14. Какие опции используются для монтирования томов? (Выбери 3)
74 |
75 | > --volume
76 | > -v
77 | > --mount
78 |
79 | 15. Какая из команд будет правильной для запуска контейнера webserver с томом secure-vol, который смонтирован в
80 | директорию назначения /opt внутри контейнера в режиме readonly? (Выбери 4)
81 |
82 | > docker run -d --name webserver --mount source=secure-vol,target=/opt,ro nginx
83 | > docker run -d --name webserver -v secure-vol:/opt:ro nginx
84 | > docker run -d --name webserver --volume secure-vol:/opt:ro nginx
85 | > docker run -d --name webserver --mount source=secure-vol,target=/opt,readonly nginx
86 |
--------------------------------------------------------------------------------
/3_docker_images/3_7_lab_commadns_entrypoints/lab5.md:
--------------------------------------------------------------------------------
1 | # Лабораторная №5 (Commadns and Entrypoints)
2 |
3 | Мы представили несколько Dockerfiles нескольких популярных продуктов в каталоге /home/moon/.
4 | Изучи их и ответь на несколько вопросов.
5 |
6 | 1. Какая ENTRYPOINT установлена для создания образа nosql базы данных?
7 |
8 | ```shell
9 | ll
10 | ```
11 |
12 | ```shell
13 | cat Dockerfile-mongodb
14 | ```
15 |
16 | 2. Какая ENTRYPOINT установлена для создания образа реляционной базы данных, коммюнити версии mysql?
17 |
18 | ```shell
19 | cat Dockerfile-mariadb
20 | ```
21 |
22 | 3. Какая CMD установлена для создания образа системы управления контентом wordpress?
23 |
24 | ```shell
25 | cat Dockerfile-wordpress
26 | ```
27 |
28 | 4. Какой будет окончательная команда при запуске контейнера из образа wordpress из данного Dockerfile? Прими во внимание
29 | и инструкцию ENTRYPOINT, и инструкцию CMD
30 |
31 | > In a Dockerfile, CMD and ENTRYPOINT are instructions used to define the default command to be executed when the
32 | > container starts.
33 |
34 | > CMD instruction is used to set the default command and/or parameters that will be executed when a new container is
35 | > started from the image. It can be overridden by specifying a command when starting the container.
36 |
37 | > For example, CMD ["python", "app.py"] sets the default command to run the app.py file with the python interpreter.
38 |
39 | > ENTRYPOINT instruction is used to set the default executable command for a container. It is the command that will be
40 | > executed when the container starts, and any arguments passed to the docker run command will be appended to the
41 | > ENTRYPOINT command.
42 |
43 | > For example, ENTRYPOINT ["python", "app.py"] sets the default executable to python app.py. When the container starts
44 | > with the command docker run myapp arg1 arg2, it will execute the command python app.py arg1 arg2.
45 |
46 | > If both CMD and ENTRYPOINT instructions are specified in a Dockerfile, CMD is used to provide default arguments for
47 | > the
48 | > command specified by ENTRYPOINT.
49 |
50 | > For example, if the Dockerfile has both ENTRYPOINT ["python"] and CMD ["app.py"], then the default command when
51 | > starting
52 | > the container will be python app.py. However, if the container is started with a command, such as docker run myapp
53 | > script.py, then the default command will be overridden and the container will execute python script.py.
54 |
55 | ```
56 | ENTRYPOINT ["docker-entrypoint.sh"]
57 | CMD ["apache2-foreground"]
58 | ```
59 |
60 | ```
61 | docker-entrypoint.sh apache2-foreground
62 | ```
63 |
64 | 5. Какая команда выполняется при запуске контейнера, созданного из Dockerfile с названием ubuntu?
65 |
66 | ```shell
67 | cat Dockerfile-ubuntu
68 | ```
69 |
70 | 6. Запусти контейнер из образа ubuntu и переопредели команду (CMD) для старта в контейнере, заменив ее на sleep 1000
71 | Запусти это в detached mode.
72 |
73 | ```docker
74 | docker run -d ubuntu sleep 1000
75 | ```
76 |
--------------------------------------------------------------------------------
/7_registry/7_3_docker_registry_test/test_registry.md:
--------------------------------------------------------------------------------
1 | # Тест: Docker Registry
2 |
3 | Подход к Registry у Docker Community Edition и Mirantis Kubernetes Engine (известный ранее как Docker Enterprise) сильно
4 | отличаются.
5 |
6 | В Docker CE ты можешь самостоятельно поднять службы реестра, настроить там аутентификацию, сканирование на уязвимости,
7 | подпись образов и т.д. В Enterprise версии все это идет из коробки.
8 |
9 | Здесь у нас будет вопрос по Docker Trusted Registry - т.е. продукта, который есть только в Docker Enterprise.
10 |
11 | Еще раз упомяну - эти тесты сложнее материала для новичков и требуются, только если ты хочешь сертификат об окончании.
12 | Если тебя это задевает и ты считаешь, что курс стал от них хуже - просто пропусти эти тесты.
13 |
14 | Эти ссылки помогут в прохождении теста:
15 |
16 | https://docs.docker.com/engine/reference/commandline/docker/
17 |
18 | https://docs.docker.com/registry/introduction/
19 |
20 | 1. Ты логинишься при помощи команды docker login , данные для аутентификации сохраняются локально. Где находятся эти
21 | креденшилс?
22 |
23 | > `$HOME/.docker/config.json`
24 | > [docker login](https://docs.docker.com/engine/reference/commandline/login/)
25 |
26 | 2. Что из этого верный адрес для докер-образа, имя которого webapp-rockets, а организация, владеющая этим образом
27 | rocketcorp, держит его в приватном реджистри по адресу registry.group-x.money?
28 |
29 | > `registry.group-x.money/rocketcorp/webapp-rockets`
30 |
31 | 3. Какая команда используется для поиска образов с именем, содержащим в себе nginx, и по крайней мере с 15 звездами? Мы
32 | хотим ограничить вывод тремя строками.
33 |
34 | > `docker search --filter=stars=15 --limit 3 nginx`
35 |
36 | 4. Какая команда поможет в поиске официального образа httpd?
37 |
38 | > `docker search --filter is-official=true httpd`
39 | > [docker search](https://docs.docker.com/engine/reference/commandline/search/)
40 |
41 | 5. Что из этого пользователь (аккаунт) и образ (репозиторий) в образе grafana/alpine?
42 |
43 | > user=grafana, image=alpine
44 |
45 | 6. Выбери особенности docker trusted registry (DTR).
46 |
47 | > Встроенный контроль доступа
48 | > Сканирование образов
49 | > Управление образами и заданиями
50 | > Подпись образов
51 | > [Docker Trusted Registry overview](https://docs.docker.com.xy2401.com/ee/dtr/)
52 |
53 | 7. Какой командой можно получить список локальных образов, имеющих метку org.opencontainers.image.title?
54 |
55 | > docker images --filter "label=org.opencontainers.image.title"
56 | > [docker images](https://docs.docker.com/engine/reference/commandline/images/)
57 |
58 | 8. Какой командой можно изменить тег webserver:latest на webserver:httpd? (Выбери 2)
59 |
60 | > docker image tag webserver:latest webserver:httpd
61 | > docker tag webserver:latest webserver:httpd
62 | > [docker image tag](https://docs.docker.com/engine/reference/commandline/image_tag/)
63 | > [docker tag](https://docs.docker.com/engine/reference/commandline/tag/)
64 |
65 | 9. Какой командой можно загрузить образ в приватный реджистри?
66 |
67 | > docker push //
68 |
69 | 10. Ты запускаешь команду docker pull rotorocloud/cosign, но получаешь ошибку. В чем дело?
70 |
71 | > У образа rotorocloud/cosign в реестре нет тега latest
72 |
--------------------------------------------------------------------------------
/5_docker_storage/5_2_lab7/lab7.md:
--------------------------------------------------------------------------------
1 | # Лабораторная №7 (Docker Engine)
2 |
3 | 1. Запусти контейнер с названием alpine-100mb из образа alpine, ограничив его память 100mb.
4 | Не забудь, что alpine это ОС, внутри должна работать какая-то команда.
5 | Проверить себя ты можешь с помощью команды docker stats --no-stream
6 |
7 | ```shell
8 | docker run --name alpine-100mb --memory=100m alpine sleep 1000
9 | ```
10 |
11 | 2. Какой из контейнеров был ограничен примерно 50% процессорного времени для своего выполнения?
12 | Запусти скрипт в размещении /home/moon/cpu-stress.sh
13 |
14 | В отличие от памяти, ограничения CPU основаны на доле совместного времени обработки процесса. Таким образом, можно
15 | приоритезировать самые важные процессы, а на не критические выделять CPU по остаточному принципу. Есть несколько
16 | способов разделить ресурсы, здесь мы воспользовались инструкцией --cpu-shares. Ты можешь изучить код в скрипте
17 |
18 | И да, в самом деле, в скрипте для контейнера stress75 установлена планка 75%, но из-за особенностей виртуализации нашей
19 | песочницы, это работает на 50%. В чистом docker будет 75%.
20 |
21 | ```bash
22 | #!/bin/sh
23 | docker run -d --name stress75 --cpuset-cpus 0 --cpu-shares 768 benhall/stress
24 | docker run -d --name stress25 --cpuset-cpus 0 --cpu-shares 256 benhall/stress
25 | sleep 5
26 | docker stats --no-stream
27 | docker rm -f stress75 stress25
28 | ```
29 |
30 | 3. Запусти команду: `docker run -it alpine ip addr show`
31 | Сколько сетевых интерфейсов у контейнера (включая loopback)?
32 |
33 | В то время, как cgroups контролируют сколько ресурсов может получить контейнер, namespaces управляют тем, что контейнер
34 | может видеть и к чему получить доступ.
35 |
36 | 4. Запусти команду: `docker run -it --net=host alpine ip addr show`
37 | Сколько теперь сетевых интерфейсов у контейнера (включая loopback)?
38 | Первая команда запускала контейнер в обычном режиме изоляции, а вторая в NET-пространстве хоста
39 |
40 | В выводе команд наглядно видно, что внутри контейнера существует единственный виртуальный eth-интерфейс (не считая
41 | loopback), но при отключении NET-изоляции контейнер получает доступ ко всем сетевым устройствам своего докер-хоста.
42 |
43 | 5. Запусти команды:
44 | `docker run -it alpine ps aux`
45 | `docker run -it --pid=host alpine ps aux`
46 | Первая команда запускает контейнер в обычном режиме изоляции, а вторая в PID-пространстве хоста
47 |
48 | В выводе команд наглядно видно, что дерево процессов в контейнере при PID-изоляции подменяется фейковым деревом.
49 |
50 | 6. Запусти контейнер в detached mode с именем http из образа nginx:alpine
51 |
52 | Иногда для целей отладки мы можем предоставить контейнеру доступ в namespaces докер-хоста. Это считается плохой
53 | практикой, поскольку мы разрушаем всю модель безопасности Docker. Вместо этого, мы можем предоставить интструментам
54 | профилирования доступ в namespaces, связанных с контейнером.
55 |
56 | ```shell
57 | docker run -d --name http nginx:alpine
58 | ```
59 |
60 | 7. Запусти команду:
61 | `docker run --net=container:http benhall/curl curl -s localhost`
62 |
63 | Контейнеры-отладчики теперь могут использовать пространство имен контейнера http. Они окажутся как бы в одной песочнице,
64 | и новый контейнер сможет обратиться к веб-серверу просто через localhost.
65 |
66 | 8. Запусти команду:
67 | `docker run --pid=container:http alpine ps aux`
68 |
69 | Та же история с процессами, их можно сделать общими. Например, ты можешь залезть в контейнер и исследовать его с помощью
70 | `strace`. И тебе не потребуется ставить дополнительное ПО в контейнер, останавливать контейнер и перезапускать приложение
71 | в нем.
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/3_docker_images/3_2_lab3/lab3.md:
--------------------------------------------------------------------------------
1 | # Лабораторная 3: образы
2 |
3 | 1. Сколько images доступно на докер-хосте?
4 |
5 | ```docker
6 | docker images
7 | ```
8 |
9 | 2. Какой размер образа ubuntu?
10 |
11 | ```docker
12 | docker images
13 | ```
14 |
15 | 3. Какой тег у нового образа NGINX?
16 | ИНФО: Мы только что спуллили новый образ.
17 |
18 | ```docker
19 | docker images
20 | ```
21 |
22 | 4. Мы только что скачали код приложения. Какой базовый образ используется в этом Dockerfile?
23 | Ищи Dockerfile в директории /var/webapp-rockets.
24 |
25 | ```shell
26 | cd /var/webapp-rockets
27 | ```
28 |
29 | ```shell
30 | ll
31 | ```
32 |
33 | ```shell
34 | cat Dockerfile
35 | ```
36 |
37 | ```
38 | FROM python:3.6
39 |
40 | RUN pip install flask
41 |
42 | COPY . /opt/
43 |
44 | EXPOSE 8080
45 |
46 | WORKDIR /opt
47 |
48 | ENTRYPOINT ["python3", "app.py"]
49 | ```
50 |
51 | 5. В какое расположение внутри контейнера будет скопирован исходный код во время создания образа?
52 | Исследуй Dockerfile в директории /var/webapp-rockets.
53 |
54 | ```shell
55 | cat Dockerfile
56 | ```
57 |
58 | 6. Когда контейнер создан с помощью этого Dockerfile, какая команда используется для запуска приложения внутри него?
59 | Исследуй Dockerfile в директории /var/webapp-rockets.
60 |
61 | ```shell
62 | cat Dockerfile
63 | ```
64 |
65 | ```shell
66 | python3 app.py
67 | ```
68 |
69 | 7. Какой port у приложения внутри контейнера?
70 | Исследуй Dockerfile в директории /var/webapp-rockets.
71 |
72 | 8080
73 |
74 | 8. Создай докер-образ используя этот Dockerfile и назови его webapp-rockets. Не присваивай никаких тегов.
75 |
76 | ```docker
77 | docker build . -f Dockerfile -t webapp-rockets
78 | ```
79 |
80 | 9. Запусти экземпляр образа webapp-rockets и опубликуй порт 8080 контейнера на 30082 порту докер-хоста.
81 |
82 | ```docker
83 | docker run -d -p 30082:8080 webapp-rockets
84 | ```
85 |
86 | 10. Открой веб-приложение используя вкладку приложения в обучающем модуле.
87 | После выполнения ты можешь остановить работающий контейнер с помощью комбинации CTRL + C или командой docker stop $(
88 | docker ps -q --filter ancestor=webapp-rockets).
89 |
90 | ```docker
91 | docker stop $(docker ps -q --filter ancestor=webapp-rockets)
92 | ```
93 |
94 | 11. Какая базовая ОС использована в образе python:3.6?
95 | Если потребуется, ты всегда можешь запустить такой контейнер.
96 |
97 | ```docker
98 | docker inspect webapp-rockets
99 | ```
100 |
101 | os: linux 64
102 |
103 | ```docker
104 | docker history webapp-rockets
105 | ```
106 |
107 | не понимаю...
108 |
109 | ```docker
110 | docker exec 705 cat /etc/os-release
111 | ```
112 |
113 | ```
114 | PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
115 | NAME="Debian GNU/Linux"
116 | VERSION_ID="11"
117 | VERSION="11 (bullseye)"
118 | VERSION_CODENAME=bullseye
119 | ID=debian
120 | HOME_URL="https://www.debian.org/"
121 | SUPPORT_URL="https://www.debian.org/support"
122 | BUG_REPORT_URL="https://bugs.debian.org/"
123 | ```
124 |
125 | 12. Какой примерный размер образа webapp-rockets?
126 |
127 | ```docker
128 | docker images
129 | ```
130 |
131 | 13. Это действительно большой размер для образа. Докер-образы предполагаются как маленькие и легковесные. Давай немного
132 | пообрежем его.
133 |
134 | 14. Создай новый образ этого приложения, который будет поменьше. Измени старый Dockerfile, назови образ webapp-rockets,
135 | дай ему тег lite.
136 | Поищи базовый образ поменьше для python:3.6. Убедись, что размер готового образа будет меньше чем 150MB.
137 | Пароль для sudo - selena
138 |
139 | ```
140 | FROM python:3.6-alpine
141 |
142 | RUN pip install flask
143 |
144 | COPY . /opt/
145 |
146 | EXPOSE 8080
147 |
148 | WORKDIR /opt
149 |
150 | ENTRYPOINT ["python3", "app.py"]
151 | ```
152 |
153 | ```docker
154 | docker build . -f Dockerfile -t webapp-rockets:lite
155 | ```
156 |
157 | 15. Запусти новый контейнер из образа webapp-rockets:lite и прокинь порт 8080 контейнера на порт 30083 докер-хоста.
158 |
159 | ```docker
160 | docker run -d -p 30083:8080 webapp-rockets:lite
161 | ```
162 |
--------------------------------------------------------------------------------
/8_container_orchestration/8_2_docker_swarm/docker_swarm.md:
--------------------------------------------------------------------------------
1 | # Docker Swarm
2 |
3 | Привет, в этой небольшой лекции я немного познакомлю тебя с Docker Swarm. Docker Swarm
4 | включает в себя много концепции и потребует своего собственного курса. Здесь я покажу
5 | основные детали, как говориться "в крупную клетку". После этого ты будешь понимать о чем речь,
6 | и, когда тебе понадобиться эта технология будешь знать, куда смотреть.
7 |
8 |
9 |
10 | С Docker Swarm ты можешь собрать несколько докер-хостов в единый кластер, который будет
11 | согласованно работать над твоими задачами. Кластер займется распределением служб или
12 | экземпляров приложений на отдельные хосты, тем самым обеспечит высокую доступность и
13 | балансировку нагрузки между различными системами и оборудованием.
14 |
15 |
16 |
17 | Для начала тебе потребуется одна или несколько машин с установленным на них Docker. После
18 | этого нужно определиться, какой из этих хостов будет использоваться в роли менеджера или
19 | мастера. Остальные хосты станут слейвами или воркерами.
20 |
21 | Затем запустим команду `docker swarm init` на менеджере для инициализации менеджера swarm.
22 |
23 | В выводе команды будет представлена команда, которую нужно запустить на воркерах, для того,
24 | чтобы рабочие экземпляры swarm смогли присоединиться к менеджеру в кластере. После
25 | присоединения к swarm рабочие хосты станут называться нодами, и теперь мы готовы создавать
26 | службы и развертывать их в кластере swarm.
27 |
28 |
29 |
30 | Давай рассмотрим некоторые подробности. Как ты помнишь ранее, чтобы запустить экземпляр
31 | моего веб-сервера мне требовалось запустить команду `docker run` и указать имя образа, который
32 | я хотел запустить. Это создаст новый контейнер с экземпляром моего приложения и в нем мой
33 | сервер начнет обслуживать клиентов.
34 |
35 | Мы уже узнали, как создать кластер swarm. А как использовать кластер для запуска нескольких
36 | экземпляров моего веб-сервера?
37 |
38 | Один из способов добиться этого - запустить команду `docker run` на каждой воркер ноде кластера.
39 | В случае пары узлов это звучит приемлемо, но если нод сотни?
40 |
41 | Т.е. мне придется придется входить на каждую из сотни нод и запускать эту команду, для этого
42 | мне нужно будет где-то держать все учетные записи или ключи для входа. Также мне придется
43 | придумать решение для балансировки нагрузки, а для этого мне потребуется также решить вопрос
44 | с мониторингом состояния узла в части его загруженности. И еще мне потребуется проверять, как
45 | чувствует себя контейнер, и живо ли мое приложение в нем, а там где произойдет сбой, мне нужно
46 | будет перезапустить контейнер самостоятельно.
47 |
48 | Такая миссия очень быстро становится невыполнимой. Процессы можно улучшить самодельной
49 | автоматизацией, но ее приходится поддерживать и со временем это превращается в уродливого
50 | монстра. И именно здесь оркестрация Docker swarm решит эти задачи за нас.
51 |
52 | Пока мы только создали этот кластер, но не видели оркестрацию в действии. Ключевым
53 | компонентом оркестрации swarm является service. Service в Docker - это один или несколько
54 | экземпляров одного приложения или службы, которые работают на нодах в кластере.
55 |
56 | Например, я создам Docker service чтобы запустить несколько экземпляров моего веб-сервера на
57 | нескольких нодах в моем swarm кластере. Для этого запущу команду `docker service create` на
58 | менеджере swarm. Я укажу имя моего образа в этой команде. А использовав параметр --replicas
59 | задам количество экземпляров этого приложения, которые мне нужно развернуть в моем
60 | кластере.
61 |
62 | Поскольку я указал три реплики, я получу три экземпляра моего веб-сервера, распределенных по
63 | разным рабочим узлам.
64 |
65 | Помни, что команда `docker service` должна запускаться на ноде-менеджере, а не на рабочем узле.
66 | Команда `docker service create` аналогична команде `docker run` в случае отдельного докер-хоста.
67 | То же самое и в отношении уже знакомых параметров, таких как -e (переменные окружения),
68 | параметра -p для публикации портов, опции --network для подключения контейнера к сети и т. д.
69 |
--------------------------------------------------------------------------------
/2_docker_commands/3_demo_commands/demo_commands.md:
--------------------------------------------------------------------------------
1 | # Demo commands
2 |
3 | Привет, и добро пожаловать на лекцию в которой мы подробнее рассмотрим особенности команды
4 | `docker run`. Это одна из наиболее часто используемых команд и у нее, наверное, больше всего
5 | параметров для запуска. Этот ряд особенностей тебе необходимо будет знать и уметь применять
6 | на практике, если ты хочешь, чтобы Docker облегчил твою жизнь. Мы попрактикуем это на
7 | лабораторной.
8 |
9 | Идем на сайт [docker hub](https://hub.docker.com/search?q=)
10 |
11 | Смотрим, какие контейнеры нам доступны.
12 |
13 | Попробуем alpine linux [alpine](https://hub.docker.com/_/alpine)
14 |
15 | Запустим его командой
16 |
17 | ```docker
18 | docker run alpine
19 | ```
20 |
21 |
22 |
23 | Если будет указано только имя образа, докер будет думать следующим образом:
24 |
25 | + репозиторий по умолчанию докерхаб
26 | + если не указано имя пользователя, то нужно искать в библиотеке официальных образов
27 |
28 | При запуске неофициального образа используется формат: имя_пользователя/имя_образа.
29 |
30 | Используем параметр `-it` для входа внутрь контейнера.
31 | `sh` - оболочка shell.
32 |
33 | ```docker
34 | docker run -it alpine sh
35 | ```
36 |
37 |
38 |
39 | ```shell
40 | hostname
41 | ```
42 |
43 |
44 |
45 | Давай посмотрим на релизную информацию этой ОС
46 |
47 | ```shell
48 | cat /etc/*rel*
49 | ```
50 |
51 |
52 |
53 | Посмотрим на список работающий контейнеров
54 |
55 | ```docker
56 | docker ps
57 | ```
58 |
59 |
60 |
61 | Запустим контейнер в фоновом режиме `-d` , чтобы открепить от него консоль и займем контейнер выполнением
62 | процесса `sleep`
63 |
64 | ```docker
65 | docker run -d alpine sleep 15
66 | ```
67 |
68 |
69 |
70 | Тебе потребуется команда, чтобы увидить все контейнеры, которые присутствуют у тебя на хосте.
71 | Как работающие, так и уже выполненные/остановленные.
72 |
73 | ```docker
74 | docker ps -a
75 | ```
76 |
77 |
78 |
79 | Запустим alpine в detached mode на 1000 секунд
80 |
81 | ```docker
82 | docker run -d alpine sleep 1000
83 | ```
84 |
85 | Чтобы прервать работу контейнера ("Убить контейнер")
86 |
87 |
88 |
89 | `docker stop (Имя или id)`
90 |
91 | ```docker
92 | docker stop nervous_tharp
93 | ```
94 |
95 | Как удалять контейнеры
96 |
97 | `docker rm (Имя или id)`
98 |
99 | ```docker
100 | docker rm
101 | ```
102 |
103 |
104 |
105 | Теперь переходим к образам
106 |
107 | ```docker
108 | docker images
109 | ```
110 |
111 |
112 |
113 | Для удаления контейнеров есть команда
114 |
115 | ```docker
116 | docker rmi alpine
117 | ```
118 |
119 |
120 |
121 | Для тестов нам потребуется образ busybox
122 |
123 | ```docker
124 | docker run -d busybox sleep 200
125 | ```
126 |
127 | Попробуем удалить образ пока работает контейнер
128 |
129 | ```docker
130 | docker rmi busybox
131 | ```
132 |
133 | ```shell
134 | Error response from daemon: conflict: unable to remove repository reference "busybox" (must force)
135 | ```
136 |
137 | Остановим контейнер.
138 | Удалим образ командой для удаления множества контейнеров/образов.
139 |
140 | ```docker
141 | docker rm $(docker ps -aq)
142 | ```
143 |
144 | Удалит все контейнеры.
145 |
146 | Чтобы скачать образ заранее, в докер есть команда:
147 |
148 | ```docker
149 | docker pull nginx
150 | ```
151 |
152 | Команда скачает докер образ на хост не запуская.
153 |
154 | Запустим его в фоновом режиме
155 |
156 | ```docker
157 | docker run -d nginx
158 | ```
159 |
160 | Чтобы посмотреть конфигурацию nginx внутри контейнера.
161 |
162 | Для начала определем id контейнера командой `docker ps`
163 |
164 | Чтобы выполнить команду в работающем контейнере введем `docker exec id_контейнера`
165 |
166 | ```docker
167 | docker exec c9c0e88d78f8 cat /etc/nginx/nginx.conf
168 | ```
169 |
170 |
171 |
172 | Помогают в решении пролем команды `docker inspect` `cocker logs`
173 |
--------------------------------------------------------------------------------
/8_container_orchestration/8_1_orchestration/orchestration.md:
--------------------------------------------------------------------------------
1 | # Оркестрация
2 |
3 | Привет и добро пожаловать на лекцию по оркестрации контейнеров. Здесь мы поговорим о том,
4 | как быть, если одного докер-хоста по каким-то причинам недостаточно для разворачивания
5 | проекта, с какими трудностями сталкиваются и как их преодолевают.
6 |
7 |
8 |
9 | Ранее в курсе мы видели, как запустить отдельный экземпляр приложения с помощью Docker.
10 | Для этого мы использовали простую команду `docker run`. В этом случае мы запускаем приложение
11 | на базе node js с помощью команды docker run node. Но это всего один экземпляр на одном
12 | докер-хосте. Что будет, если количество пользователей возрастет настолько, что у запущенного
13 | инстанса не станет хватать ресурсов, чтобы справиться с нагрузкой?
14 |
15 | Ты можешь развернуть дополнительный экземпляр своего приложения с помощью такой же
16 | команды `docker run` и повторить это несколько раз. Т.е. тебе придется самому следить за
17 | нагрузкой и производительностью приложения, соответственно реагировать запуская или
18 | останавливая дополнительные копии приложения. А если контейнер выйдет из строя, тебе нужно
19 | это обнаружить и снова запустить команду docker run, чтобы развернуть другой экземпляр
20 | приложения.
21 |
22 | А что с докер-хостом? Надо знать как он себя чувствует, мониторить его ресурсы. Что если хост
23 | упадет и станет недоступным? В этом случае все наше приложение перестанет отвечать
24 | пользователям.
25 |
26 | Если мы начнем решать все эти проблемы самостоятельно, то потребуется минимум отдельный
27 | инженер, который будет заниматься мониторингом состояний производительности и здоровья
28 | контейнеров и хоста и, при необходимости, исправлять ситуацию. Если твое приложение
29 | действительно большое, скажем от тысячи контейнеров, такой подход совершенно неприменим.
30 |
31 | Разумеется можно начать самому автоматизировать эти процессы, написав какие-то скрипты. И
32 | это будет как-то работать. Проблемы начнуться очень скоро, когда:
33 |
34 | - поменяются сотрудники - новых придется переучивать,
35 | - ротируются разработчики, у других может быть свой взгляд на автоматизацию,
36 | - постоянно появляются новые технологии, которые требуют новых интеграций,
37 | - появятся вызовы безопасности, которые вскроют все проблемы непродуманной
38 | архитектуры или каких-то временных компромиссов, сделанных для упрощения в прошлом.
39 |
40 |
41 |
42 | Решения по оркестрации контейнеров помогут нам в этом случае. Эти решения содержат в себе
43 | набор подходов, технологий и инструментов, которые обслуживают контейнерные нагрузки в
44 | продакшене. Как правило, подобное решение реализует в себе несколько докер-хостов, чтобы в
45 | случае неисправности одного из них работа не останавливалась, и пользователь не замечал
46 | простоя.
47 |
48 | В случае проблем, система оркестрации сама переключит пользователя на другой докер-хост и
49 | попробует вернуть в строй неисправный. Также эти решения для оркестрации позволяет легко
50 | развернуть сотни или тысячи экземпляров приложения с помощью одной команды.
51 |
52 | Эта команда используется в Docker swarm. Мы ее немного рассмотрим в следующей лекции.
53 |
54 | Некоторые решения для оркестрации могут помочь нам автоматически увеличить количество
55 | экземпляров при увеличении количества пользователей, и уменьшить количество экземпляров при
56 | уменьшении спроса. Часть решений могут даже помочь нам в автоматическом добавлении
57 | дополнительных хостов для поддержки пользовательской нагрузки, а не только в кластеризации и
58 | масштабировании количества контейнеров.
59 |
60 | Также они обеспечивают поддержку специальной сети между этими контейнерами на разных
61 | хостах, и обслуживают балансировку нагрузки пользовательских запросов между разными
62 | докер-хостами. Из этих решений можно осуществлять управление конфигурацией и безопасностью
63 | в кластере и обеспечивать совместное использование хранилища между хостами.
64 |
65 |
66 |
67 | Сегодня доступно несколько систем для оркестрации контейнеров. У Docker это решение Docker
68 | Swarm, Kubernetes от Google и MESOS от Apache.
69 |
70 | По сравнению с другими, Docker Swarm очень легко настроить и начать пользоваться, это хорошее
71 | решение для начала. Но с другой стороны в нем не хватает многих нужных функций, которые
72 | требуются для сложных приложений.
73 |
74 | В случае с MESOS его намного сложнее установить и настроить, но он предлагает много
75 | продвинутого функционала.
76 |
77 | Kubernetes из этих трех самый популярный:
78 |
79 | - он не такой сложный в настройке, с ним можно быстро начать работу.
80 | - он дает большое количество вариантов развертывания и поддерживает сложные
81 | архитектуры
82 |
83 | Kubernetes в данный момент поддерживается всеми клауд-вендорами, такими как GCP, Azure, AWS,
84 | Alibaba, а проект Kubernetes один из популярнейших на гитхаб.
85 |
--------------------------------------------------------------------------------
/6_network/6_1_network_in_docker/network_in_docker.md:
--------------------------------------------------------------------------------
1 | # Сеть в Docker
2 |
3 |
4 |
5 | Когда мы устанавливаем Docker, он автоматически создает три сети:
6 | - bridge
7 | - none
8 | - host
9 |
10 | Мостовая (bridge) сеть - это сеть по умолчанию, к которой подключается контейнер. Если мы хотим
11 | связать контейнер с любой другой сетью, то потребуется явно указать информацию о сети.
12 | Используй параметр --network командной строки, как я показал на экране. Мы сейчас рассмотрим
13 | каждую из этих сетей поближе.
14 |
15 | Сеть Bridge - это частная внутренняя сеть, созданная Docker на хосте. Все контейнеры подключены
16 | к этой сети по умолчанию. Как правило диапазон этих внутренних IP-адресов 172.17, но это
17 | настраивается. Контейнеры получают доступ друг к другу, используя этот внутренний IP-адрес.
18 | Если требуется доступ к какому-то из этих контейнеров из внешнего мира, нужно сопоставить
19 | порты контейнеров с портами на докер-хосте.
20 |
21 | Другим способом доступа к контейнерам извне, о котором я упомянул, является вариант прямого
22 | связывания контейнера с сетью хоста. Это убирает всю сетевую изоляцию между докер-хостом и
23 | докер-контейнером. Что будет означать, если мы запускаем веб-сервер на порту 5000 в
24 | веб-контейнере, он автоматически становится доступным извне на том же порту своего хоста, без
25 | необходимости какого-либо сопоставления портов.
26 |
27 | Здесь этот веб-контейнер будет использовать все сетевые ресурсы своего хоста. И это также
28 | будет означать, что, в отличие от прошлого примера, теперь мы не сможем запускать несколько
29 | контейнеров в одном хосте на одном и том же порту. Поскольку теперь нет ни внутренних и не
30 | внешних портов, порты являются общими. Службы самого хоста, разумеется, также занимают
31 | какие-то порты, и это нужно учитывать размещая контейнеры в сети типа host.
32 |
33 | Теперь сеть none. Контейнеры не являются членами какой-либо сети и не имеют доступа к внешней
34 | сети или другим контейнерам, которые запущены в изолированных сетях.
35 |
36 | На самом деле это еще не все. Для нагрузок, связанных с оркестрацией есть тип сети Overlay. Этот
37 | тип сети адаптирован для работы одной сети на нескольких узлах. Далее в Docker есть тип Macvlan,
38 | она будет интересна, если ты собираешься докеризировать нагрузки, которые раньше
39 | размещались в виртуальных машинах, эта штука полностью эмулирует физический хост в части
40 | сети. Также Docker позволяет с разной степенью успешности интегрировать кастомные сетевые
41 | плагины.
42 |
43 | Эти сети узко специфичные, и о них мы будем говорить в продвинутом курсе Docker.
44 |
45 | Итак, мы только что увидели мостовую сеть по умолчанию с идентификатором 172.17.0.1. Таким
46 | образом, все контейнеры, ассоциированные с этой сетью, смогут общаться друг с другом.
47 |
48 |
49 |
50 | Но что, если мы хотим изолировать контейнеры внутри докер-узла, например, первые два
51 | контейнера во внутренней сети 172 и два вторых контейнера в другой внутренней сети, например 182?
52 |
53 | По умолчанию Docker создает только одну внутреннюю мостовую сеть. Но мы можем сами создать
54 | свою собственную внутреннюю сеть с помощью команды `docker network create` и указать тип сети
55 | в параметре --driver, в нашей команде это bridge.
56 |
57 | Мы указываем диапазон адресации новой сети в CIDR нотации после параметра --subnet. В этом
58 | случае 182.18.0.0/16 и за ним следует пользовательское имя этой новой изолированной сети.
59 | Теперь запустим команду `docker network ls`, чтобы вывести список всех сетей.
60 |
61 |
62 |
63 | Для того, чтобы увидеть настройки сети и IP-адрес, назначенный существующему контейнеру,
64 | запустим команду `docker inspect` с названием контейнера или его ID. Там, в разделе
65 | NetworkSettings -> Networks мы можем увидеть тип сети, к которой контейнер привязан, его
66 | внутренний IP-адрес, Mac-адрес.
67 |
68 |
69 |
70 | Как ты помнишь в bridge network другие контейнеры могут связываться друг с другом, используя
71 | свои имена. Например, здесь у меня есть веб-сервер и контейнер базы данных MySQL, работающие
72 | на одном хосте в одной сети. Как я могу реализовать доступ для моего веб-сервера к базе данных в
73 | контейнере?
74 |
75 | Один из вариантов, который я мог бы сделать - это использовать внутренний IP-адрес,
76 | назначенный контейнеру MySQL, который в данном случае 172.17.0.3. Но это не очень правильно,
77 | поскольку не гарантируется, что контейнер получит тот же IP-адрес, когда система перезагрузится
78 | или контейнер по какой-то причине сломается и его место займет новый. Лучший способ сделать
79 | это - использовать имя контейнера.
80 |
81 | Все контейнеры на докер-хосте могут находить адреса друг друга с помощью имени контейнера.
82 | Docker имеет встроенный DNS-сервер, который помогает контейнерам разрешать имена друг друга.
83 | Обрати внимание, что встроенный (embedded) DNS-сервер всегда работает по адресу 127.0.0.11.
84 | Вот так Docker реализует сети. А какие технологии стоят за этим?
85 |
86 | Это изоляция network namespace. Т.е. для каждого контейнера используется свое пространство
87 | имен, которые позволяют разному трафику передаваться и обрабатываться по разным правилам, и
88 | делать это рядом друг с другом и незаметно друг для друга. Также используются виртуальные
89 | Ethernet адаптеры для соединения контейнеров вместе.
90 |
--------------------------------------------------------------------------------
/3_docker_images/3_8_test_images/test_images.md:
--------------------------------------------------------------------------------
1 | # Тест: Images
2 |
3 | Есть несколько best practices при создании образов для докер-контейнеров. Эти рекомендации помогают получить
4 | производительные и безопасные решения.
5 |
6 | А именно, это такие вещи, как:
7 |
8 | + контроль за базовыми образами, на которых построены твои образы
9 | + контроль за размером образа
10 | + контроль за пакетами в образе
11 | + контроль за уязвимостями в образе
12 | + контроль за хранением в образе
13 |
14 | Для каждого из этих векторов есть специальные методы оценки и митигации. На моем ресурсе rotoro.cloud в курсе Certified
15 | Kubernetes Security Specialist мы подробно обсуждаем эти вопросы и учимся собирать образы правильно. Если у тебя там
16 | есть подписка, можешь пройти те лабораторные.
17 |
18 | Еще раз упомяну - эти тесты сложнее материала для новичков и требуются, только если ты хочешь сертификат об окончании.
19 | Если тебя это задевает и ты считаешь, что курс стал от них хуже - просто пропусти эти тесты.
20 |
21 | Вот полезные ссылки:
22 |
23 | https://docs.docker.com/engine/reference/builder/
24 |
25 | https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
26 |
27 | https://docs.docker.com/language/golang/build-images/
28 |
29 | https://docs.docker.com/build/building/multi-stage/
30 |
31 | https://docs.docker.com/build/building/context/
32 |
33 | https://docs.docker.com/engine/reference/commandline/history/
34 |
35 | 1. После сборки образ назвали parser. Что произойдет, если мы запустим команду: docker run parser sleep 1h?
36 |
37 | > Dockerfile:
38 | > FROM ubuntu:20.04
39 | > COPY . /app
40 | > RUN make /app
41 | > CMD python /app/app.py
42 |
43 | ```
44 | Docker изменит инструкцию CMD на 'sleep 1h'
45 | ```
46 |
47 | 2. Выбери инструкцию CMD для команды echo -n "My home is $HOME", которая выводит значение переменной окружения и
48 | считается предпочитаемой.
49 |
50 | > The CMD instruction is used to specify the default command to run when a container is started from the Docker image.
51 | > The
52 | > CMD instruction allows you to set a default command or parameters, which can be overridden by users when they run the
53 | > container.
54 |
55 | > In this example CMD [ "sh", "-c", "echo -n My home is $HOME" ], the default command is set to run the shell (sh) and
56 | > execute the command echo -n My home is $HOME. The command will print the string "My home is" followed by the value of
57 | > the $HOME environment variable. The -n option is used to suppress the newline at the end of the output.
58 |
59 | > The CMD instruction must be specified in the Dockerfile, and it is the last command that is executed when the
60 | > container
61 | > is started. If there are multiple CMD instructions in the Dockerfile, only the last one will be executed. If a user
62 | > specifies a command to run when starting the container, it will override the CMD instruction in the Dockerfile.
63 |
64 | ```
65 | CMD [ "sh", "-c", "echo -n My home is $HOME" ]
66 | ```
67 |
68 | 3. Мы решили создать свой образ и в процессе его сборки требуется скачать файл с https://rootfs.tar.xz и автоматически
69 | распаковать пути /. Какую команду выбрать?
70 |
71 | ```
72 | ADD https://rootfs.tar.xz /
73 | ```
74 |
75 | 4. Что поможет уменьшить размер образа?
76 |
77 | ```
78 | 1. Установка только необходимых пакетов в образ
79 | 2. Использовать multi-stage сборки
80 | 3. Предотвращение копирования нежелательных файлов в контекст сборки при помощи '.dockerignore'
81 | 4. Комбинирование нескольких инструкций в одну и очистка временных файлов в этой же инструкции
82 | ```
83 |
84 | 5. Как определить, что Dockerfile содержит в себе multi-stage?
85 |
86 | ```
87 | В Dockerfile присутствуют несколько инструкций FROM
88 | ```
89 |
90 | 6. Изучи Dockerfile. Какое значение нужно добавить после флага --from во второй стадии сборки, чтобы скомпилированный
91 | бинарник go-приложения из первой стадии был помещен в финальный образ?
92 |
93 | ```
94 | Dockerfile:
95 |
96 | FROM golang:1.12-alpine as builder
97 |
98 | ENV GO111MODULE=on
99 |
100 | WORKDIR /app
101 | COPY . .
102 |
103 | RUN apk --no-cache add git alpine-sdk build-base gcc
104 |
105 | RUN go get \
106 | && go get golang.org/x/tools/cmd/cover \
107 | && go get github.com/mattn/goveralls
108 |
109 | RUN go build -o example cmd/example/main.go
110 |
111 | FROM alpine:latest
112 | RUN apk --no-cache add ca-certificates
113 | WORKDIR /root/
114 | COPY --from=<неизвестно> /app/example .
115 | CMD ["./example"]
116 | ```
117 |
118 | ```
119 | builder
120 | ```
121 |
122 | 7. Какая команда напечатает значения 'Architecture' и 'Os' образа с названием rockets?
123 |
124 | ```docker
125 | docker image inspect rockets -f '{{.Os}} {{.Architecture}}'
126 | ```
127 |
128 | 8. Если мы используем CMD для предоставления аргумента по умолчанию для инструкции ENTRYPOINT, то должны быть указаны
129 | обе инструкции, как CMD, так и ENTRYPOINT?
130 |
131 | ```
132 | Да
133 | ```
134 |
135 | 9. Какая команда удалит все неиспользуемые образы на докер-хосте?
136 |
137 | ```docker
138 | docker image prune -a
139 | ```
140 |
141 | 10. Как собрать образ при помощи Dockerfile из директории /opt/prj01/, используя для контекста путь /opt/prj01/v2 и
142 | назвать этот образ app:v2?
143 |
144 | ```
145 | У нас есть директория с
146 |
147 | $ tree /opt/prj01/
148 | /opt/prj01/
149 | |-- Dockerfile
150 | |-- v1
151 | | `-- app.py
152 | `-- v2
153 | `-- app.py
154 | ```
155 |
156 | ```docker
157 | docker build /opt/prj01/v2 -f /opt/prj01/Dockerfile -t app:v2
158 | ```
159 |
160 | 11. Как увидеть список всех слоев образа redis вместе с размером каждого слоя?
161 |
162 |
--------------------------------------------------------------------------------
/4_docker-compose/4_2_test_compose/test_compose.md:
--------------------------------------------------------------------------------
1 | # Тест: Compose
2 |
3 | > Для работы с docker-compose требуются знания YAML. В версии Stepik в курсе нет лекции по YAML, но она и
4 | > соответствующая лабораторная есть в моем курсе Ansible https://stepik.org/course/123806 или в курсе Docker для
5 | > начинающих на https://rotoro.cloud в разделе приложений, проверь это, если еще не знаком с этим языком разметки.
6 | > Как обычно, эти тесты основаны не только на материалах лекций - отнесись к этому с пониманием и учись работать с
7 | > документацией.
8 | > Еще раз упомяну - эти тесты сложнее материала для новичков и требуются, только если ты хочешь сертификат об окончании.
9 | > Если тебя это задевает и ты считаешь, что курс стал от них хуже - просто пропусти эти тесты.
10 | > Эти ссылки помогут в прохождении теста:
11 | > https://docs.docker.com/compose/reference/
12 | > https://docs.docker.com/compose/compose-file/
13 | > https://rotoro.cloud/topic/%d0%b2%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-yaml/
14 |
15 | 1. При помощи чего мы можем настроить контейнеры и связь между ними используя декларативный подход?
16 |
17 | > Docker Compose
18 |
19 | 2. Какой YAML-файл, содержащий описание services, networks и volumes для развертывания контейнеризированного приложения,
20 | обычно используется?
21 |
22 | > docker-compose.yaml
23 |
24 | 3. Какая команда используется для создания и запуска контейнеров на переднем плане, используя готовый файл
25 | docker-compose.yaml?
26 |
27 | > docker-compose up
28 |
29 | 4. Какая команда используется для создания и запуска контейнеров на заднем плане, используя готовый файл
30 | docker-compose.yaml?
31 |
32 | > docker-compose up --detach
33 | > docker-compose up -d
34 |
35 | 5. Как посмотреть список созданных compose контейнеров?
36 |
37 | > docker-compose ps
38 |
39 | 6. Какая команда поможет в проверке логов всего стека, указанного в docker-compose.yaml?
40 |
41 | > docker-compose logs
42 |
43 | 7. Какой командой можно остановить (не удаляя) весь стек контейнеров, описанных в compose-файле?
44 |
45 | > docker-compose stop
46 |
47 | 8. Какой командой можно удалить весь стек контейнеров, описанных в compose-файле?
48 |
49 | > docker-compose down
50 |
51 | 9. Как используется поле version в compose-файле? (выбери 3)
52 |
53 | > docker-compose использует максимально последнюю подходящую схему, не ориентируясь на версию
54 | > Поле версии носит лишь информативный характер
55 | > docker-compose анализирует файл и самостоятельно принимает решение о том, по схеме какой версии работать
56 |
57 | > Top-level version property is defined by the specification for backward compatibility but is only informative.
58 | > A Compose implementation SHOULD NOT use this version to select an exact schema to validate the Compose file, but
59 | > prefer
60 | > the most recent schema at the time it has been designed.
61 | >
62 | >Compose implementations SHOULD validate whether they can fully parse the Compose file. If some fields are unknown,
63 | > typically because the Compose file was written with fields defined by a newer version of the specification, Compose
64 | > implementations SHOULD warn the user. Compose implementations MAY offer options to ignore unknown fields (as defined
65 | > by “loose” mode).
66 |
67 | 10. Compose-файлы версий 2 и 3 должны явно указывать свою версию в корневом разделе YAML документа?
68 |
69 | > Да
70 |
71 | > Вкратце, композ парсит файл и по инструкциям сам понимает, до какой версии опускаться. Но версии все же нужно
72 | > указывать, это нужно не только в информационных целях для пользователей, которые смотрят в репо с развертыванием, но и
73 | > для композа, поскольку версии 2 и 3 несовместимы, и он это проверяет, если хотят применить третью поверх второй
74 | > например.
75 |
76 | 11. Используя команду docker-compose up мы можем поднять несколько контейнеров на разных докер-хостах?
77 |
78 | > Нет
79 |
80 | 12. На какой порт хоста будет выставлено приложение при исполнении docker-compose up -d?
81 |
82 | ```
83 | docker-compose.yaml:
84 |
85 | version: "3.8"
86 | services:
87 | web:
88 | build: .
89 | depends_on:
90 | - db
91 | - redis
92 | volumes:
93 | - .:/code
94 | - logvolume01:/var/log
95 | ports:
96 | - "8080:80"
97 | redis:
98 | image: redis
99 | db:
100 | image: postgres
101 | volumes:
102 | logvolume01: {}
103 | ```
104 |
105 | > 8080
106 |
107 | 13. Что из утверждений верно?
108 |
109 | ```
110 | docker-compose.yaml:
111 |
112 | version: "3.8"
113 | services:
114 | web:
115 | build: .
116 | depends_on:
117 | - db
118 | - redis
119 | volumes:
120 | - .:/code
121 | - logvolume01:/var/log
122 | ports:
123 | - "8080:80"
124 | redis:
125 | image: redis
126 | db:
127 | image: postgres
128 | volumes:
129 | logvolume01: {}
130 | ```
131 |
132 | > Образ web будет собран, а образы redis и postgres будут скачаны с Dockerhub, если их еще нет на хосте
133 |
134 | 14. Что можно сказать о монтированиях для службы web в этом compose-файле?
135 |
136 | > Примечание: о монтировании мы будем говорить в теме хранения
137 |
138 | ```
139 | docker-compose.yaml:
140 |
141 | version: "3.8"
142 | services:
143 | web:
144 | build: .
145 | depends_on:
146 | - db
147 | - redis
148 | volumes:
149 | - .:/code
150 | - logvolume01:/var/log
151 | ports:
152 | - "8080:80"
153 | redis:
154 | image: redis
155 | db:
156 | image: postgres
157 | volumes:
158 | logvolume01: {}
159 | ```
160 |
161 | > /code это Bind Mount, /var/log это Volume mount
162 |
163 | 15. Что из утверждений верно об этом файле?
164 |
165 | ```
166 | docker-compose.yaml:
167 |
168 | version: "3.8"
169 | services:
170 | web:
171 | build: .
172 | depends_on:
173 | - db
174 | - redis
175 | volumes:
176 | - .:/code
177 | - logvolume01:/var/log
178 | ports:
179 | - "8080:80"
180 | redis:
181 | image: redis
182 | db:
183 | image: postgres
184 | volumes:
185 | logvolume01: {}
186 | ```
187 |
188 | > Службы redis и db должны будут запуститься до службы web
189 |
--------------------------------------------------------------------------------
/9_YAML/YAML.md:
--------------------------------------------------------------------------------
1 | # Введение в YAML
2 |
3 | Привет и добро пожаловать на лекцию, где мы узнаем, что такое YAML файлы. Если ты знаком с
4 | YAML файлами, просто пропусти этот раздел. Но если ты не еще работал с YAML до этого времени,
5 | я сильно рекомендую тебе внимательно пройти эту лекцию и упражнения, потому что многое в
6 | курсе зависит от знания YAML. Если ты работал с другими форматами структурирования данных,
7 | такими как XML или JSON, ты легко все поймешь. Не волнуйся, если ты не работал ни с одним из
8 | них. Тытакже все легко поймешь, проработав навык в упражнениях, которые сопровождают курс.
9 | YAML файл используется для представления данных, в нашем случае для файлов конфигурации.
10 |
11 |
12 |
13 | Здесь быстрое сравнение образцов одинаковых данных в трех разных форматах. Левый это XML,
14 | где мы представили список серверов и информацию о них. Те же данные представлены в JSON
15 | формате посередине. И, наконец, YAML формат справа. Посмотри внимательно на форматы и
16 | сравни их.
17 |
18 |
19 |
20 | Давай взглянем ближе на YAML. Если взять данные в простейшей форме вроде "ключ-значение",
21 | вот как это выглядит в YAML. Ключ и значение разделено двоеточием. Ключи это: fruit, vegetable,
22 | liquid, и meat. Значения: apple, carrot, water, и chicken. Запомни, после двоеточия должен идти
23 | пробел, который разделит ключ и значение.
24 |
25 | Теперь посмотрим, как представлен массив. Мы хотели бы перечислить несколько фруктов и
26 | овощей. Напишем fruits, за которым следует двоеточие. Далее в каждый элемент массива
27 | напишем с новой строки с тире впереди. Тире обозначает, что это элемент массива.
28 |
29 | Что насчет ассоциативных массивов? Dictionary это набор свойств, сгруппированный вместе под
30 | одним элементом. Здесь мы попробуем представить пищевую ценность двух фруктов. Калории,
31 | жир, углеводы и белки отдельно для каждого фрукта. Обрати внимание на пустое место перед
32 | каждым элементом dictionary. Перед свойствами отдельного элемента должно быть равное
33 | количество пробелов, чтобы у них было одинаковое выравнивание.
34 |
35 |
36 |
37 | Теперь взглянем внимательнее на пробелы в YAML. Здесь у нас dictionary, представляющий
38 | пищевую ценность банана. Показаны общее количество калорий, жира, углеводов и белка. Обрати
39 | внимание, количество пробелов перед каждым элементом определяет, что эти пары
40 | "ключ-значение" относятся к банану. Что произойдет, если добавить дополнительные пробелы для
41 | fat, carbs и protein?
42 |
43 | Они попадут в категорию калорий, т.е. станут свойствами калорий, в чем нет никакого смысла. Еще
44 | это приведет к синтаксической ошибке, которая сообщит, что сопоставление значений здесь
45 | недопустимо, поскольку у ключа calories есть уже значение 102. Ты можешь присвоить ключу -
46 | значение, или установить его как название для низлежащего объекта, но только что-то одно.
47 | Количество пробелов перед каждым свойством является ключевым в YAML. Убедись в
48 | правильности расстановки пробелов, чтобы данные были представлены как предполагалось.
49 |
50 |
51 |
52 | Усложним задачу. Давай создадим list, содержащий dictionaries. В этом случае у нас есть list
53 | фруктов - fruits. Его элементы банан и яблоко. Каждый из этих элементов представляет из себя
54 | dictionary, в котором содержится пищевая ценность.
55 |
56 |
57 |
58 | Большинство новичков в YAML задают мне вопрос: что лучше использовать dictionary или list?
59 | Попробую объяснить по-понятнее. Во первых, и это важно понять, то, о чем мы говорим далеко от
60 | XML, JSON, или YAML, которые используются для представления данных. У нас могут быть данные
61 | организации и всех их сотрудников с персональными деталями, или данные школы со всеми ее
62 | студентами, их отметками, или данные автопроизводителя о выпущенных машинах и их деталях.
63 | Все что угодно.
64 |
65 | Возьмем для примера автомобильный фургон. Машина это отдельный объект. Ее свойства это:
66 | цвет, цена, трансмиссия и модель. Для хранения разной информации или свойств объекта мы
67 | используем dictionary. В этом простом dictionary свойства машины представлены в формате
68 | "ключ-значение".
69 |
70 | Все может стать сложнее, например нам нужно разделить свойство model на название модели и
71 | год выпуска. Это можно представить как dictionary внутри другого dictionary. Тогда значение поля
72 | model заменится небольшим dictionary с двумя свойствами name и year. Это dictionary в другом
73 | dictionary.
74 |
75 | Теперь поговорим, как хранить имена четырех машин. Имена сформированы из цвета и модели
76 | фургона. Для хранения этого мы будем использовать list или array, т.к. у нас много элементов
77 | одного и того же вида. Мы храним только имена, и это простой массив строк.
78 |
79 | Т.е. если информация однотипная, хорошо подойдет list, а если разнородная - dictionary.
80 |
81 | А что, если мы захотим сохранить всю информацию о каждой машине? Все, что мы перечисляли
82 | раньше: цвет, цену, трансмиссию и модель. Нам нужно будет изменить list of strings на list of
83 | dictionaries. Мы расширяем каждый элемент в list и меняем имя на созданный ранее dictionary.
84 |
85 | Таким образом, у нас получилось представить всю информацию о множестве фургонов в одном
86 | YAML файле используя list of dictionaries. В этом различие между list и list of dictionaries.
87 |
88 | Надеюсь, различия стали очевидны и тебе стало проще понимать, когда какие использовать.
89 |
90 |
91 |
92 | Перед началом упражнений давай примем во внимание пару особенностей формата. Dictionary - это
93 | коллекция не требовательная к порядку элементов, в отличие от list, которые порядок соблюдают.
94 |
95 | Что это значит? Два dictionaries представленных здесь имеют одинаковые свойства для banana, но
96 | порядок свойств не совпадает. В первом fat идет после calories, а во втором наоборот.
97 |
98 | В случае dictionary это не имеет значения, свойства могут быть определены в любом порядке. Два
99 | dictionaries будут считаться идентичными, пока все значения всех их свойств совпадают.
100 |
101 | Это не относится к массивам. Lists - упорядоченные коллекции, здесь порядок элементов имеет
102 | значение. В этом случае два lists не одинаковые, потому что яблоко и апельсин на разных позициях.
103 | Не забудь об этом, когда будешь работать со структурами данных
104 |
105 | Еще момент, любая строка начинающаяся с символа ХЭШ (#) будет автоматически
106 | проигнорирована парсером, она рассматривается как комментарий.
107 |
--------------------------------------------------------------------------------
/8_container_orchestration/8_3_kubernetes/kubernetes.md:
--------------------------------------------------------------------------------
1 | # Kubernetes
2 |
3 | Привет, в этой лекции мы делаем краткое введение в базовые концепции Kubernetes. Kubernetes
4 | требует своего собственного курса, даже не одного, а целых четырех. Сейчас мы постараемся
5 | кратко познакомиться с ним, на том уровне, чтобы не пугаться при беседе о Kubernetes.
6 |
7 | Итак, с помощью Docker мы смогли запустить один экземпляр приложения, введя в докер-cli
8 | команду `docker run`, которая запустила контейнер. И теперь наша жизнь изменилась, ведь прежде
9 | развертывание приложений никогда не было таким простым.
10 |
11 |
12 |
13 | С Kubernetes, использующим Kubernetes-cli, известный как утилита управления kube control, мы
14 | можем запустить нужное нам количество экземпляров одного и того же приложения с помощью
15 | всего одной команды.
16 |
17 | Kubernetes может легко отмасштабировать количество реплик приложения до нужных нам
18 | значений с помощью другой команды.
19 |
20 | Kubernetes можно даже настроить на автоматическое выполнение этой операции, чтобы
21 | экземпляры и сама инфраструктура могли масштабироваться вверх и вниз, в зависимости от
22 | пользовательской нагрузки.
23 |
24 | Kubernetes может обновлять тысячи экземпляров приложения в режиме последовательного
25 | обновления по одному, группами или все разом с помощью всего одной команды.
26 |
27 | Если что-то пойдет не так, он может откатить все эти развертывания с помощью одной команды и
28 | вернуться на предыдущую рабочую версию.
29 |
30 | Kubernetes может помочь нам устроить A-B тесты для новых фич нашего приложения, обновив
31 | только нужный процент экземпляров, благодаря возможности указания количества реплик для
32 | каждой версии.
33 |
34 | Открытая архитектура Kubernetes обеспечивает поддержку множества различных сетей и
35 | хранилищ. Любая торговая марка сетей или хранилища, о которой ты можешь подумать, имеет
36 | плагин для Kubernetes. Kubernetes поддерживает различные механизмы аутентификации и
37 | авторизации. Все основные поставщики облачных сервисов имеют встроенную поддержку
38 | Kubernetes.
39 |
40 | Итак, какова связь между Docker и Kubernetes? Kubernetes использует докер-хосты для
41 | размещения приложений в виде контейнеров Docker. Но это не обязательно должен быть Docker
42 | все время, Kubernetes поддерживает в качестве альтернативы Dockers, например, Rkt или Cri-o. Но
43 | по факту на rkt редко где встретишь, и этот проект более не развивается. Так что в реальном мире
44 | это или Docker, или Cri-o. И последний завоевывает позиции. Т.к. Docker многофункциональный
45 | инструмент, он не очень хорошо вписывается в роль только среды для запуска контейнеров,
46 | которую в нем видит Kubernetes. Cri-o, в свою очередь, имеет более оптимизированный и
47 | легковесный инструмент для запуска контейнеров и продвинутые возможностями для их
48 | траблешутинга.
49 |
50 | В момент написания статьи уже объявлено, что Kubernetes перестанет поддерживать Docker в
51 | качестве container runtime. Это не значит, что эра докер-контейнеров прошла, они как раз
52 | остануться, но похоже, что самого докера в Kubernetes со временем не останется.
53 |
54 | Давай вернемся к основной теме и кратко рассмотрим архитектуру Kubernetes.
55 | Кластер представляет из себя набор узлов - nodes.
56 |
57 |
58 |
59 | Нода это машина, физическая или виртуальная, на которой установлен Kubernetes. Воркер нода, это
60 | узел, на котором Kubernetes будет запускать контейнеры с полезной нагрузкой. Раньше они
61 | назывались миньонами. Услышав этот термин имей в виду, что это синонимы. Что случится, если
62 | нода выйдет из строя?
63 |
64 | Очевидно, что наше приложение упадет. Выходит, нам нужно иметь больше одной ноды. Кластер -
65 | это набор сгруппированных вместе узлов. Таким образом, даже если один узел падает, наше
66 | приложение по-прежнему доступно для пользователей. Более того, наличие нескольких нод также
67 | помогает в распределении нагрузки.
68 |
69 |
70 |
71 | Ок, теперь у нас есть кластер, но кто будет отвечать за его управление? Где будет храниться
72 | информация о членах кластера? Как нам узнать о событиях, происходящих на нодах? А когда нода
73 | выйдет из строя, как перенести рабочую нагрузку с упавшей ноды на исправную?
74 |
75 | Вот здесь появляется мастер, или как теперь его политкорректно называют controlplane. Мастер
76 | это еще одна нода, член кластера Kubernetes, сконфигурированная как мастер. У нее особые
77 | функции: наблюдать за состоянием других нод и быть ответственной за оркестрацию контейнеров
78 | на воркер-нодах.
79 |
80 |
81 |
82 | Когда ты устанавливаешь Kubernetes в систему, ты фактически устанавливаешь следующие
83 | компоненты:
84 |
85 | - API сервер
86 | - Контейнер рантайм
87 | - контроллеры и скедулеры
88 | - службу kubelet
89 | - службу ETCD
90 |
91 | API сервер выступает в качестве фронтенда, единого интерфейса для Kubernetes. Пользователи,
92 | устройства управления, интерфейсы командной строки, все общаются с API сервером для
93 | взаимодействия с кластером.
94 |
95 | Среда выполнения контейнеров или контейнер-рантайм - это базовое программное обеспечение,
96 | которое используется для запуска контейнеров. В нашем случае это Docker, но есть и другие
97 | варианты.
98 |
99 | Контроллеры - это мозг оркестрации. Они смотрят за состоянием нод, контейнеров, эндпоинтов и
100 | ответственны за реакцию на события на нодах. Контроллеры принимают решения о создании
101 | новых контейнеров.
102 |
103 | Скедулер ответственен за распределение работ или контейнеров между нодами. Он ожидает, когда
104 | в системе появится новый контейнер, чтобы назначить его выполнение на ноду.
105 |
106 | Далее kubelet - это агент, который работает на каждом узле кластера. Агент отвечает за то, чтобы
107 | контейнеры работали на узлах должным образом.
108 |
109 | И, наконец, ETCD - хранилище "ключ-значение". ETCD - это распределенная, надежная база данных,
110 | используемая Kubernetes для хранения всей информации нужной для управления кластером.
111 |
112 | И в конце нам нужно немного узнать об утилите командной строки kubectl или kube control, как ее
113 | еще называют. Инструмент kubectl используется для развертывания и управления приложениями в
114 | кластере Kubernetes, для получения информации о кластере, получения состояния других нод в
115 | кластере и управления другими вещами.
116 |
117 |
118 |
119 | Команда `kubectl run` используется для развертывания приложения в кластере.
120 |
121 | Команда `kubectl cluster-info` используется для просмотра информации о кластере.
122 |
123 | Команда `kubectl get nodes` используется для вывода списка всех узлов в кластере.
124 |
125 | Как я говорил, это мощный инструмент и одной командой можно внести изменения в тысячи копий
126 | приложения на сотнях узлов.
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/3_docker_images/3_6_commands_and_entrypoint/c_n_e.md:
--------------------------------------------------------------------------------
1 | # Привет и добро пожаловать на лекцию, где мы поговорим о аргументах команд и точках входа в Docker.
2 |
3 |
4 |
5 | Начнем с простого сценария. Предположим, что мы запустили контейнер с образом ubuntu. Когда
6 | мы ввели команду `docker run ubuntu`, Docker запустил экземпляр образа ubuntu и немедленно
7 | сделал выход из контейнера.
8 |
9 | Если сейчас посмотреть список работающих контейнеров, то мы не увидим их. Если же запустить
10 | `docker ps -a`, тем самым запросив список всех контейнеров на хосте, мы увидим наш новый
11 | контейнер, он будет остановлен со статусом exited. Почему это не работает как виртуальная
12 | машина?
13 |
14 |
15 |
16 | Как мы уже говорили, контейнеры не предназначены для размещения операционных систем.
17 |
18 | Они подходят для некоторых процессов вроде запуска веб-сервера, базы данных или
19 | аналитической задачи. Когда задача завершена, контейнер останавливается. Жизнь в нем
20 | поддерживает работающий внутри процесс. Т.е. если веб-сервер, или база данных, или другой
21 | запущенный процесс внутри контейнера остановится или скрашится, то контейнер немедленно
22 | выйдет. Итак, что определяет, какой процесс будет запущен в контейнере?
23 |
24 |
25 |
26 | Если посмотреть на Dockerfile такого популярного приложения как nginx ты увидишь инструкцию
27 | CMD. Эта инструкция определяет команду, которая будет запускаться в контейнере при запуске
28 | его из образа. Это команда nginx. Для официального образа MySQL в Dockerfile будет команда
29 | mysqld.
30 |
31 |
32 |
33 | Ранее мы пытались запустить контейнер с пустой ОС Ubuntu. Посмотрим на Dockerfile этого образа
34 | и мы увидим, что команда по умолчанию там bash. Но как мы знаем bash это не совсем такой
35 | процесс, вроде веб-сервера или базы данных. Это оболочка, которая ждет ввода с терминала и,
36 | если если она не может найти терминал, она завершается. Когда мы запускали контейнер с Ubuntu
37 | ранее, Docker создавал контейнер из образа Ubuntu и запускал программу bash по умолчанию.
38 | Терминал к контейнеру при запуске Docker не подключал.
39 |
40 | Таким образом, программа bash не находила терминал и завершала работу.
41 | А поскольку процесс, который был запущен при создании контейнера, завершался, то и контейнер
42 | также останавливался. Как нам указать другую команду при старте контейнера?
43 |
44 |
45 |
46 | Один из вариантов - добавить нужную команду к `docker run` и таким образом переопределить
47 | команду по умолчанию, указанную в образе.
48 |
49 | В этом случае мы выполним:
50 | `docker run Ubuntu с командой sleep 5` в качестве дополнительного параметра.
51 |
52 | Теперь, когда контейнер стартует, будет запущена команда sleep. Она будет выполняться 5 секунд,
53 | после чего удачно завершится, что соответственно и завершит выполнение контейнера. Как
54 | сделать эти изменения постоянными? Скажем, тебе нужно всегда запускать команду sleep.
55 |
56 |
57 |
58 | Создай свой собственный образ из базового образа ubuntu и укажи новую команду с помощью
59 | инструкции CMD. Есть несколько разных возможностей указать команду:
60 | - как ты ее пишешь в шелле
61 | - в виде JSON-массива
62 |
63 |
64 | Не забудь, если ты укажешь это в JSON, первым элементом массива должен быть исполняемый
65 | файл. В этом случае инструкция CMD написана неверно. "sleep 5" команда и параметр указаны
66 | вместе. Это не сработает, команда и параметры должны быть разнесены в отдельные элементы
67 | массива.
68 |
69 | Ок, с помощью Dockerfile который ты видишь, я создам свой новый образ ubuntu-sleeper с
70 | помощью команды: `docker build ubuntu-sleeper`
71 |
72 | Теперь можно просто запустить его контейнер используя: `docker run ubuntu-sleeper`
73 |
74 | Я получил предполагаемый результат - контейнер запускается, ждет 5 секунд и выходит. Это
75 | количество секунд захардкожено в моей инструкции CMD. Как мне изменить этот промежуток, не
76 | меняя образ?
77 |
78 |
79 |
80 | Один из путей запустить контейнер с добавлением новой команды:
81 | `docker run ubuntu-sleeper sleep 10`
82 |
83 | В этом случае команда sleep 10 выполнится при старте и успешно отработает положенные ей 10
84 | секунд. Но это решение так себе. Само название ubuntu-sleeper подразумевает, что контейнер будет
85 | спать, не хотелось бы дополнительно указывать инструкцию вроде "проспи 10 секунд".
86 |
87 | Что-то более изящное, например не указывать команду sleep, а указать только количество нужных
88 | секунд, что-то вроде: `docker run ubuntu-sleeper 10`. Я хочу, чтобы контейнер меня при этом понял и
89 | автоматически вызвал команду sleep с моим параметром. Вот здесь появляется инструкция
90 | ENTRYPOINT.
91 |
92 | Инструкция ENTRYPOINT похожа на инструкцию CMD, в ней ты также указваешь программу или
93 | команду, которая будет запущена в контейнере, а также все дополнительные аргументы, которые
94 | ты бы указал в командной строке. В этом случае 10 будет добавлено в значение ENTRYPOINT и
95 | будет собрана единая команда. Таким образом контейнер запустится с командой sleep 10.
96 |
97 | В этом отличия этих двух инструкций. В случае инструкции CMD переданные параметры командной
98 | строки будут полностью заменены, тогда как в случае ENTRYPOINT эти параметры будут
99 | добавлены. Что случится, если я запущу docker run ubuntu-sleeper без добавления количества
100 | секунд?
101 |
102 | Здесь к команде sleep добавится пустой параметр, т.е. образуется просто команда sleep, и я получу
103 | сообщение об отсутствии операнда. Значит, хорошо бы иметь значение по умолчанию на такой
104 | случай.
105 |
106 |
107 |
108 | Этого можно добится используя обе инструкции сразу: ENTRYPOINT и CMD. В ENTRYPOINT пропишу
109 | исполняемую команду, а в CMD значение аргумента по умолчанию. Теперь команда для старта в
110 | контейнере соберется из ENTRYPOINT и значения из CMD, т.к. мы не передали аргументов в
111 | командную строку и тем самым не переопределили CMD. Таким образом получим команду sleep 5.
112 | Если же мы укажем параметр, то инструкция CMD будет переопределена, как в случае с sleep 10.
113 |
114 | Запомни, чтобы это сработало всегда нужно указывать ENTRYPOINT и CMD в формате JSON.
115 |
116 | И наконец, что, если нам потребуется изменить ENTRYPOINT во время выполнения? Использовать
117 | какую-то другую команду, например заменить sleep на super-sleep. Это возможно используя
118 | праметр --entrypoint.
119 |
120 | `docker run --entrypoint super-sleep ubuntu-sleeper 10`
121 |
122 | В этом случае контейнер будет запущен с командой super-sleep 10 внутри.
123 |
124 | Это все в этой лекции, давай погрузимся в практику с нашими лабораторными.
125 |
--------------------------------------------------------------------------------
/2_docker_commands/8_test/test.md:
--------------------------------------------------------------------------------
1 | # Тест
2 |
3 | ## Как удалить все запущенные и остановленные контейнеры на хосте?
4 |
5 | > + docker container rm -f $(docker container ls -aq)
6 | > + docker container rm -f $(docker container ps -aq)
7 | > + docker rm -f $(docker ps -aq)
8 | > Note that the difference between docker rm and docker container rm is simply that the latter explicitly refers to
9 | container objects (introduced in Docker 1.13) while the former uses the legacy syntax.
10 | > the "ls" command is an alias for "ps"
11 |
12 | ## Какая из команд создаст (не запустит) контейнер с образом redis и именем redis?
13 |
14 | > + docker container create --name redis redis
15 | > When you run this command, Docker will create a new container based on the redis image and name it redis. However,
16 | the container will not be started yet. You can start the container later using the docker container start redis
17 | command.
18 | > docker container create [OPTIONS] IMAGE [COMMAND] [ARG...]
19 | то есть нельзя после названия образа писать опции к команде create, например имя контейнера --name
20 |
21 | ## Мы развернули несколько контейнеров. Как увидеть, какой из них потребляет больше всего памяти?
22 |
23 | > + docker container stats
24 | > The docker container stats command is used to display real-time usage statistics for running containers. It
25 | provides a live stream of resource usage metrics such as CPU usage, memory consumption, network I/O, and disk I/O
26 | for one or more running containers.
27 |
28 | ## Как запустить контейнер с названием webserver с образом nginx в интерактивном режиме? (Выбери 2)
29 |
30 | > + docker run -it --name webserver nginx
31 | > + docker container run -it --name webserver nginx
32 |
33 | ## Какая команда используется для обновления restart policy контейнера redis в значение always?
34 |
35 | > + docker container update --restart always redis
36 | > The docker container update command is used to update the configuration of an existing container. The --restart
37 | option is used to set the restart policy for the container. The always option for the --restart option means that
38 | Docker will always attempt to restart the container if it stops for any reason, including if the Docker daemon is
39 | restarted.
40 |
41 | ## Как скопировать директорию nginx из контейнера webapp на хост по пути /tmp/?
42 |
43 | > + docker container cp webapp:/etc/nginx /tmp/
44 | > The command docker container cp webapp:/etc/nginx /tmp/ is used to copy the nginx directory from the container
45 | webapp to the /tmp/ directory on the host. Here's what each part of the command means:
46 |
47 | > docker container cp is the command to copy files and directories between a container and the host.
48 |
49 |
50 | > webapp is the name or ID of the container from which the files will be copied.
51 | > :/etc/nginx is the path of the directory to be copied inside the container. In this case, it is the nginx directory
52 |
53 | > located in the /etc directory.
54 |
55 | > /tmp/ is the path of the directory on the host where the directory will be copied to.
56 |
57 | > When this command is executed, Docker will create the /tmp/nginx directory on the host machine (if it doesn't
58 | > exist
59 | > already), and copy the entire nginx directory from the webapp container to it. This can be useful if you need to
60 | > access
61 | > files or configurations from a container on the host machine for debugging or testing purposes.
62 |
63 | ## Можно ли сопоставить несколько контейнеров с одним и тем же портом к одному порту на докер-хосте?
64 |
65 | > нет
66 |
67 | ## Какой командой мы можем проверить драйвер логирования по умолчанию?
68 |
69 | > [ChatGPT]: docker info --format '{{.LoggingDriver}}'
70 | >
71 | > correct answer: docker system info
72 | >
73 | > The docker system info command displays system-wide information about the Docker installation on the host. It includes
74 | > information about the Docker version, operating system, number of containers and images, storage driver, logging
75 | > driver,
76 | > and other useful details about the Docker environment.
77 |
78 | ## Как запустить контейнер redis и быть уверенным, что для него не будет настроено логов?
79 |
80 | > [ChatGPT]: docker run -d --name redis --log-driver=none redis
81 | >
82 | > correct answer: `docker run -it -d --log-driver none redis`
83 | >
84 | > By setting the logging driver to "none", you're telling Docker not to collect or store any logs for the Redis
85 | > container. This can be useful if you don't need or want to log Redis's output, or if you want to reduce the amount of
86 | > data that Docker has to store. However, it's important to note that disabling logging altogether can make it harder to
87 | > debug problems with your container later on.
88 |
89 | ## Как проверить статус службы docker на хосте?
90 |
91 | > sudo systemctl status docker
92 |
93 | ## При помощи какого механизма Docker сопоставляет порты контейнера и хоста?
94 |
95 | > При помощи правил IPTables
96 | >
97 | > Docker uses IPTables to perform port mapping between the container and the host. When a Docker container starts, it
98 | > creates a network namespace with its own network stack that includes its own IP address and set of network interfaces.
99 | > To allow communication between the container and the host, Docker sets up IPTables rules that map the container's
100 | > ports
101 | > to the host's ports. Specifically, Docker creates DNAT rules (Destination Network Address Translation) that redirect
102 | > incoming traffic to the container's IP address and port to the corresponding port on the host. These rules are created
103 | > in the nat table of the host's IPTables. When the response is sent back, the IPTables rules are used again to
104 | > translate
105 | > the source address of the response to the container's IP address and port. This way, the container appears to be
106 | > directly connected to the network with its own IP address and ports, even though it is running in a separate network
107 | > namespace.
108 |
109 | ## Какой флаг настроит Docker на проброс порта 80 UDP в контейнере на порт 8080 докер-хоста?
110 |
111 | > -p 8080:80/udp
112 | >
113 | > In the example -p 8080:80/udp, the host port 8080 is mapped to the container port 80 using the UDP protocol. This
114 | > means that any traffic sent to the Docker host on port 8080 using UDP protocol will be forwarded to the container on
115 | > port 80 using the same protocol.
116 | >
117 | > This is useful for applications that require a specific port and protocol to be used for communication, such as some
118 | > video streaming applications that use UDP instead of TCP for lower latency.
119 |
120 | ## Если не указано иное, Docker публикует открытый порт на всех сетевых интерфейсах?
121 |
122 | > Yes, by default Docker publishes an open port on all network interfaces (0.0.0.0). This means that the container's
123 | > port can be accessed from any IP address on the host machine's network.
124 | >
125 | > However, you can also specify a specific network interface to bind to by specifying the interface's IP address when
126 | > publishing the port. For example, -p 127.0.0.1:8080:80 would only bind the container's port 80 to the localhost
127 | > interface (127.0.0.1) on the host machine.
128 |
129 | ## Какой командой мы можем получить сводку важной информации о контейнере webapp (например сетевые адреса, переменные окружения, политику рестарта и т.д.)?
130 |
131 | > docker container inspect webapp
132 |
133 | ## Чем из приведенного мы можем получить поток логов контейнера my-app?
134 |
135 | > + docker container logs -f my-app
136 |
--------------------------------------------------------------------------------
/7_registry/7_1_docker_registry/registry.md:
--------------------------------------------------------------------------------
1 | # Docker Registry
2 |
3 | Привет. В этой лекции мы посмотрим на Docker registry.
4 |
5 |
6 |
7 | Реджистри - это сервер, который позволяет поддерживать репозитории докер-образов. Он
8 | позволяет хранить и распространять эти образы.
9 |
10 | Иногда это выражение используют в более широком смысле, говоря о реджистри, как о том месте,
11 | где хранятся образы. Мы уже привыкли, что образы лежат на докерхабе, но это не всегда верно. В
12 | продакшене в основном используют частные докер-реджистри.
13 |
14 | Для построения добротных DevSecOps-конвейеров используют приватные репозитории, в которых
15 | образы проходят необходимые этапы тестирования, секьюрити и комплаенс проверки. Также эти
16 | реджистри используют при разработке для кэширования часто используемых образов (в свете
17 | введенных Docker ограничений это актуально) или для пуллинга предварительно подготовленных
18 | образов, когда в компании существует явный запрет на пользование 3rd party images. В основном
19 | из-за соображений безопасности.
20 |
21 | Есть различные варианты размещения данных серверов: в облаке, он-премис для компании или
22 | локально для небольшой команды разработчиков. Есть менеджед решения, где вы получаете
23 | обслуживаемый репозиторий (например jfrog) или как платформу (например gcr.io).
24 |
25 |
26 |
27 | Ок, давай посмотрим на простой контейнер nginx, который мы запустили в Docker следующей
28 | командой: `docker run nginx`.
29 |
30 | Давай подробнее рассмотрим это название образа. Его имя - nginx, но что это за образ и откуда он
31 | взят? Это имя соответствует соглашению об именовании образов Docker, “nginx” здесь название
32 | образа или имя репозитория.
33 |
34 | Когда мы сказали Docker nginx, то на самом деле это nginx/nginx. Первая часть обозначает
35 | пользователя или аккаунт. Поэтому, если мы не предоставили название аккаунта или имя
36 | репозитория, предполагается, что оно совпадает с указанным, которым в данном случае является
37 | nginx.
38 |
39 | Имя пользователя обычно - это имя твоей учетной записи Docker Hub или, если это организация, то
40 | имя этой организации. Если ты используешь свою собственную учетною запись и создаешь свои
41 | собственные репозитории и образы в них, тебе нужно использовать аналогичный шаблон. А где эти
42 | образы хранятся и откуда они извлекаются?
43 |
44 | Поскольку мы не указали место, откуда эти образы должны быть извлечены, то предполагается,
45 | что он находится в докер-реджистри по умолчанию, а это как мы знаем Docker Hub. DNS-имя
46 | которого - Docker.io.
47 |
48 | В реестре хранятся все образы. Каждый раз, когда мы создаем новый образ или обновляем
49 | существующий, мы помещаем его в реджистри, и каждый раз, когда кто-либо развертывает это
50 | приложение, оно извлекается из этого реестра. Есть также много других популярных реестров.
51 |
52 | Например, реджистри от Google. Находится он по адресу GCR.io, и я знаю, что там хранится много
53 | образов связанных с Kubernetes, например их средства для тестирования кластера. Мы можем
54 | запросить эти e2e-тесты из глобальной версии их реджистри, или из версий с географической
55 | привязкой, для уменьшения latency при запросах из твоего региона.
56 |
57 | Все это общедоступные образы, которые может загрузить любой пользователь, и свободно
58 | использовать для собственных приложений. Но когда мы не хотим выносить это на публику, то
59 | размещение внутреннего частного реджистри может быть хорошим решением.
60 |
61 | Многие поставщики облачных услуг, такие как AWS, Azure, GCP или Alibaba предоставляют частные
62 | реджестри, когда мы открываем у них учетную запись. В любом из решений, будь то реджистри
63 | Docker Hub, Google или свой внутренний частный реестр, мы можем сделать репозиторий частным,
64 | чтобы к нему можно было получить доступ только с помощью набора учетных данных.
65 |
66 |
67 |
68 | С точки зрения Docker, для запуска контейнера с использованием образа из приватного реджистри
69 | cначала нужно выполнить аутентификацию в свой частный реестр с помощью команды `docker
70 | login` и ввода своих учетных данных. После этого данные для входа сохраняются на докер-хосте и
71 | при взаимодействии с этим реджистри будут использованы.
72 |
73 | Для запуска приложения используй название частного реджистри как часть имени образа, как ты
74 | видишь на экране. Если ты попробуешь обратиться за образом в частный реджистри, не войдя в
75 | него, то получишь сообщение, что образ не может быть найден. Поэтому не забудь всегда входить
76 | в систему, прежде чем пушить или пуллить в частный реджистри.
77 |
78 |
79 |
80 | Я сказал, что облачные провайдеры, такие как AWS или GCP, предоставляют возможность
81 | использования своих реджистри, когда мы создаем у них учетную запись. Но что, если мы
82 | запускаем свое приложение он-премис и не имеем доступа к частному реджистри? Как развернуть
83 | собственный частный реестр в своей организации?
84 |
85 | ПО Docker registry это не часть поставки Docker, это само по себе другое приложение. И, конечно же,
86 | он доступен как докер-образ, его можно развернуть с docker hub. После запуска он предоставляет
87 | свои API-вызовы по умолчанию на порту 5000 нашего локального хоста. Как нам закачать туда свой
88 | собственный образ?
89 |
90 | Используя команду `docker image tag`, чтобы пометить образ для частного реджистри, в который
91 | мы хотим это положить. В данном случае это localhost:5000/my-image. Поскольку реджистри
92 | работает на том же хосте, я обращаюсь к нему как localhost, далее использую двоеточие и порт
93 | 5000, за которым следует имя образа.
94 |
95 | После этого я могу отправить этот образ в свой локальный частный реджистри с помощью
96 | команды `docker push` и нового имени образа. Чтобы забрать этот образ я должен указать полное
97 | имя своего образа в соответствии с соглашением docker, т.е. `docker pull localhost:5000/my-image`.
98 | Как ты понимаешь, сделать это я смогу, только с данного докер-хоста, в котором это имя будет
99 | разрешено правильно.
100 |
101 | Другие машины из локальной сети смогут к нему обратиться с использованием IP адреса (или
102 | доменного имени) в качестве имени частного реджистри. Например 192.168.56.100:5000/my-image.
103 | Но это будет работать только в случае insecure реджистри и с костылями с сопоставлением имен. Я
104 | бы не советовал так делать.
105 |
106 | Для того, чтобы локальный докер реджистри корректно работал, требуется удостоверить имя
107 | данного реджисти с помощью изданного SSL-сертификата. Это может быть сертификат
108 | удостоверяющего центра (в случае наличия домена) или можно настроить реджистри для
109 | взаимодействия с самоподписанным сертификатом (действительно для IP адреса или имени
110 | хоста). Но в этом случае следует позаботиться, чтобы все клиенты реджистри имели его
111 | сертификат в качестве корневого, иначе они не будут ему доверять.
112 |
113 | Как я говорил есть еще вариант инсекьюрного реджистри, без сертификата. Это
114 | практиковалось какое-то время назад, но в данный момент быстрее выпустить самоподписанный
115 | сертификат или настроить ротацию бесплатных с помощью certbot или подобным, нежели
116 | переконфигурирования докера и реджистри, чтобы все работало в обход проверки подлинности.
117 |
118 | В докментации Docker разобрано несколько примеров запуска реджистри:
119 |
120 | - с отдельным контейнером
121 | - с помощью docker-compose
122 | - в инфраструктуре docker swarm.
123 |
--------------------------------------------------------------------------------
/3_docker_images/3_1_docker_images/docker_images.md:
--------------------------------------------------------------------------------
1 | # Образы докер
2 |
3 | Итак, мы решили создать свой собственный образ. Но для начала давай определимся зачем мы это
4 | делаем, зачем нам свой образ?
5 |
6 | Возможно мы не можем найти какой-то компонент или службу для своего приложения. Или мы
7 | хотим контейнеризировать свое приложение для обеспечения простоты тестирования, доставки и
8 | развертывания. А быть может мы собрали несколько уникальных окружений для компиляции
9 | исполняемых файлов и используем это в своих CICD-конвейерах. Перечислять можно много, важно,
10 | что нам не обойтись готовым решением из публичных репозиториев.
11 |
12 | В этом случае я собираюсь контейнеризировать свое простое веб-приложение. Оно написано на
13 | python с фреймворком flask. Вначале нужно понять, что мы положим в контейнер или с каким
14 | приложением мы собираемся создавать образ.
15 |
16 | Давай поразмышляем, как бы это было, если бы мы развёртывали это приложение вручную.
17 | Записав требуемые шаги в правильном порядке мы создадим план для создания нашего простого
18 | приложения.
19 |
20 |
21 |
22 | Итак, для начала в ручном режиме я бы установил себе операционную систему, например ubuntu.
23 | Далее я бы обновил apt-репозитории используя `apt update`. После этого с помощью `apt install
24 | python` установил бы python с соответствующими зависимостями и утилитами. Затем с помощью
25 | `pip install flask` создал бы необходимый для этого фреймворка базис. Осталось скопировать мой
26 | исходный код в нужную папку, например /opt/. Последний шаг - запустить код нашего веб-сервера,
27 | используя специфичную для flask команду. Ок, теперь с помощью этих инструкций мы запросто
28 | создадим свой первый Dockerfile.
29 |
30 | Вот краткий обзор процесса создания собственного docker-image:
31 | создай файл с именем Dockerfile и запиши туда инструкции по настройке своего приложения, такие
32 | как установка зависимостей, место, куда копировать исходный код приложения, какая точка входа
33 | будет использована и т.д. После этого, создай свой образ при помощи команды `docker build`,
34 | указав Dockerfile и теги для образа. Это создаст локальный докер-образ в твоей системе.
35 |
36 | Чтобы сделать его доступным в публичном докер-репозитории, вроде Docker Hub используй
37 | команду `docker push` command с указанием имени только что созданного образа. В этом случае
38 | команда будет содержать имя моего аккаунта на Docker hub - rotorocloud, а дальше имя образа -
39 | webapp.
40 |
41 |
42 |
43 | Давай познакомимся поближе с этим Dockerfile. Он пишется в специальном формате, который
44 | понятен Docker и состоит из инструкций и аргументов.
45 |
46 | Все, что в Dockerfile написано слева заглавными буквами будет считаться инструкцией. Я выделил
47 | эти места красным цветом текста. В нашем случае это: FROM, RUN, COPY, ENTRYPOINT. Все они
48 | являются инструкциями. Каждая из них указывает Docker выполнить определенное действие в
49 | процессе создания образа.
50 |
51 | Все, что правее инструкций - это аргументы. Т.е. в первой строке FROM - инструкция, а Ubuntu -
52 | аргумент.
53 |
54 | Наша первая строка определяет, какая базовая ОС будет использоваться для строительства образа
55 | и запуска контейнера из него в дальнейшем. Каждый докер-образ базируется на подобном
56 | базовом image. Т.е. на образе ОС или другом образе, который был создан на основе образа ОС.
57 | Официальные релизы популярных ОС размещены на Docker Hub, ты их сможешь легко найти для
58 | своих экспериментов. Еще раз отмечу, что все Dockerfiles начинаются с инструкции FROM, не
59 | забывай об этом.
60 |
61 | Инструкция RUN дает указание Docker запустить данные тобой команды на этом базовом образе.
62 | Мы видим, что Docker запустил команду apt-get для получения обновленных пакетов и установки их
63 | на наш базовый "голый" образ Ubuntu. Такой же инструкцией RUN он запустил команду pip install,
64 | тем самым установив зависимости для python. Напомню, что все действия производятся в
65 | изоляции и к нашей хостовой ОС отношения не имеют.
66 |
67 | После завершения инструкций RUN, инструкция COPY копирует файлы из директории нашей
68 | локальной ОС в этот собирающийся образ. В этом случае исходный код нашего python-приложения
69 | находится в папке, из которой мы запустили команду `docker build` и мы скопируем его в
70 | расположение /opt внутри образа Docker.
71 |
72 | И, наконец, последняя здесь инструкция ENTRYPOINT. Она позволяет нам указать команду, которая
73 | сработает, когда образ будет запущен в качестве контейнера.
74 |
75 |
76 |
77 | Когда Docker создает образы они строятся по слоеной (layered) архитектуре. Каждая новая
78 | инструкция создает новый слой в докер-образе, который хранит в себе отличия от предыдущего
79 | слоя.
80 |
81 | Например, за первым слоем базовой ОС Ubuntu следует инструкция, которая создаст второй слой, в
82 | котором будет установлены apt-пакеты, за ним последует третий слой, который создаст третья
83 | команда, установившая пакеты python. Четвертый слой скопирует исходный код и последний
84 | пятый слой обновит точку входа этого образа.
85 |
86 | Поскольку каждый слой хранит только изменения предыдущего слоя, это значительно отражается
87 | на размере. Взгляни, базовый образ Ubuntu имеет размер в районе 84mb. Apt установит нужные нам
88 | пакеты - это еще около 456mb. Оставшиеся слои еще меньше. Ты можешь посмотреть
89 | информацию о слоях с помощью команды `docker history` указав имя образа, который создавал.
90 |
91 |
92 |
93 | Во время сборки образа команда `docker build` выводит все шаги, которые она делает, какие
94 | команды запускает и их результат. Все слои кэшируются, поэтому слоеная архитектура помогает
95 | тебе как в случае ошибок при сборке, так и при проведении повторной сборки образа. Тебе не
96 | нужно начинать все сначала - Docker перестроит только те слои, в которые были внесены
97 | изменения.
98 |
99 | У каждого слоя есть свой хеш, по которому Docker отслеживает их уникальность
100 |
101 |
102 |
103 | Например, при сборке на четвертом шаге произошел сбой. Мы разобрались и уточнили причину
104 | сбоя. Теперь мы перезапустим сборку и увидим, что старые три слоя были переиспользованы из
105 | кэша, а фактическое исполнение команд Docker начал только с четвертого шага.
106 |
107 | Тоже самое будет, если ты изменишь одну из команд - низлежащие под ней слои (т.е. слои,
108 | которые были выполнены до этой инструкции) не будут затронуты, но будет перестроен слой
109 | измененной команды и все слои после нее. Эти новые слои также добавятся в общий кэш докера.
110 | Это позволяет создавать образы быстрее, тебе не нужно ждать команды, которые уже до этого
111 | были выполнены.
112 |
113 | Это очень полезно при обновлении исходного кода приложения. Обычно исходный код в
114 | контейнере подвергается изменению гораздо чаще, чем библиотеки и зависимости, поэтому
115 | копирование файлов приложения находится обычно в конце Dockerfile
116 |
117 |
118 |
119 | Мы уже видели ряд продуктов, содержащихся в контейнерах, таких как операционные системы,
120 | системы управления базами данных и т. д. Но это еще не все. Ты можешь создавать
121 | контейнеризированные версии практически любых приложений от серверных высоконагруженных
122 | до клиентских повседневных. Контейнерные версии бизнес-приложений тоже уже очень
123 | популярны. Это могут быть большие приложения или простые утилиты, главное, чтобы решение в
124 | контейнере было удобнее в использовании, чем классическое с инсталляцией.
125 |
126 | Также большое удобство здесь в том, что тебе сразу может быть доступно несколько версий
127 | одного приложения, обычно несовместимых в одной "песочнице". Второе удобство, что контейнер
128 | после себя не оставляет столько мусора, как в случае с простой установкой приложения и от него
129 | очень просто избавиться.
130 |
131 | Это все в этой лекции, увидимся в следующей!
132 |
133 | > Новые команды docker:
134 | > docker build . -t имя - собрать образ из dockerfile в каталоге .
135 | > docker push имя - загрузить образ в репозиторий
136 | > docker history имя - информация о слоях образа
137 |
138 | > Работа с dockerfile:
139 | > FROM - образ на базе которого создается новый образ контейнера
140 | > RUN - запустить команду на указанном образе
141 | > COPY app.py /opt/app.py - скопировать файл app.py в образ в каталог /opt/app.py
142 | > ENTRYPOINT - процесс запускаемый в контейнере
143 |
--------------------------------------------------------------------------------
/5_docker_storage/5_1_docker_engine/engine.md:
--------------------------------------------------------------------------------
1 | # Среда выполенения
2 |
3 | Добро пожаловать на эту лекцию о движке Docker. В этой лекции мы более подробно рассмотрим
4 | архитектуру Docker, на чем основана магия изоляции контейнеров и какие технологии у него "под
5 | капотом".
6 |
7 |
8 |
9 | Движок Docker (Docker engine), как мы узнали ранее, работает на хосте с установленным Docker.
10 | Это такой комбайн, который умеет многие вещи:
11 |
12 | - собирать образы
13 | - запускать контейнеры
14 | - транспортировать образы
15 | - оркестрировать контейнеры (в случае swarm)
16 | - обслуживать отдельные слои
17 | - делать траблешутинг
18 |
19 | С одной стороны это удобно, с другой стороны универсальность сыграла с Docker в минус. Об этом
20 | мы поговорим еще в разделе окрестрации. В данный момент речь об архитектуре.
21 |
22 | Итак, когда мы устанавливаем Docker на хост Linux, фактически мы устанавливаем три разных
23 | компонента:
24 |
25 | - Демон Docker
26 | - REST API-сервер
27 | - приложение командной строки докера.
28 |
29 | Docker-daemon - это фоновый процесс, который управляет объектами Docker, такими как образы,
30 | контейнеры, тома и сети.
31 |
32 | API-сервер Docker поддерживает API, который программы могут использовать для общения с
33 | демоном и предоставления инструкций. Ты можешь создать свои собственные инструменты,
34 | используя этот REST API. Кстати, на этом принципе построены наши лабораторные работы.
35 |
36 | Docker cli - это утилита командной строки, которую мы использовали до сих пор для выполнения
37 | таких действий, как запуск и остановка контейнеров, уничтожение образов и т. д. Она использует
38 | вызовы REST API для взаимодействия с демоном Docker.
39 |
40 | Следует отметить, что утилита командной строки Docker не обязательно должна находиться на
41 | одном хосте. Этим докер-хостом может быть другая система, например, я могу управлять
42 | серверным удаленным движком Docker, работающим на сервере в ДЦ со своего ноутбука. Чтобы
43 | использовать такой вызов к команде docker нужно добавить параметр -H, далее указать адрес
44 | удаленного хоста и его порт. Также можно проиниализировать переменную окружения
45 | DOCKER_HOST для постоянных вызовов к определенному хосту.
46 |
47 | Как показано здесь, для запуска контейнера на основе Nginx на удаленном хосте Docker запустим
48 | команду: `docker -H 10.10.10.1:2375 run nginx`
49 |
50 |
51 |
52 | Теперь давай попробуем разобраться, как именно в Docker контейнеризирует приложения чуть
53 | ниже уровнем, что называется "под капотом".
54 |
55 | В случае Linux Docker использует пространство имен (namespaces linux) для изоляции
56 | идентификаторов процессов рабочего пространства, подключения к сети, системы разделения
57 | времени Unix. Процессы контейнера выполняются в их собственном пространстве имен, тем
58 | самым обеспечивая изоляцию с другими процессами. Если тебе не очень ясно, это нормально.
59 | Когда я впервые об этом услышал, я ничего не понял, поскольку раньше не встречался с
60 | namespaces.
61 |
62 |
63 |
64 | Давай посмотрим на пару примеров. Сначала как работает изоляция процессов - изоляция в PID
65 | namespace.
66 |
67 | Всякий раз, когда система Linux загружается, она запускается только с одного процесса. У него
68 | process identificator = 1. Так устроен Linux. Это корневой процесс, запускающий все остальные
69 | процессы, они как бы отпочковываются от него. После загрузки у нас бежит несколько процессов
70 | одновременно. Выполним команду `ps`, чтобы вывести список всех запущенных процессов.
71 | Процессы уникальны, и два процесса не могут иметь одинаковый идентификатор процесса.
72 |
73 | Теперь, мы создали контейнер, он будет похож на дочернюю систему, размещенную в текущей
74 | системе. Дочерняя система должна думать, что она является независимой системой, что она сама
75 | по себе. Таким образом у нее должен быть свой собственный набор процессов, порожденных от
76 | корневого процесса №1, а также прочие атрибуты независимой системы.
77 |
78 | Да, как видишь у нее присутствует процесс с ID 1, но мы знаем, что между контейнерами и базовым
79 | хостом нет жесткой изоляции. Таким образом, процессы, выполняемые внутри контейнера, на
80 | самом деле являются процессами, выполняемыми на базовом хосте. Но у двух процессов не
81 | может быть одного и того же PID. Для хоста все процессы должны быть уникальны. Но внутри
82 | контейнера все иначе. Он по другому нумерует процессы, он же считает себя независимым.
83 |
84 | Нам нужно как-то урегулировать этот конфликт. Здесь вступает в игру PID namespace. Эта штука
85 | позволяет добавить к процессу помимо его настоящего ID еще и другой. Также она будет понимать,
86 | каким службам давать первичный PID, а кому "фейковый". С каждым процессом может быть
87 | связано несколько таких ID процесса.
88 |
89 | В нашем случае, когда процессы запускаются в контейнере, это фактически просто еще один набор
90 | процессов в базовой системе Linux, и они получат следующий доступный идентификатор процесса
91 | в хостовой системе. Т.е. пять и шесть. Однако, они также получают другой идентификатор процесса
92 | начиная с PID 1 в пространстве имен контейнера, которое видно только внутри контейнера. Наш
93 | контейнер имеет собственное корневое дерево процессов и поэтому является независимой
94 | системой. Точнее считает себя таковой. Итак, как это связано с реальной системой?
95 |
96 | Допустим я запустил на своем хосте с адресом 10.0.0.13 другую ОС в контейнере с адресом
97 | 172.17.0.2.
98 |
99 | Теперь я зайду с двух терминалов на докерхост и в контейнер.
100 | И там и там я выполню команду `ps aux`.
101 |
102 | В контейнере я увижу два процесса:
103 |
104 | - с PID 1, это bash в котором я нахожусь
105 | - с PID 10 это только что выполненная команда `ps aux`
106 |
107 | На хосте после целой простыни процессов, в конце я увижу интересные для меня:
108 |
109 | - с PID 2945 это bash, который работает в данный момент в контейнере
110 | - с PID 3119 это `ps aux`, который только отработал в контейнере
111 | - с PID 3129 это `ps aux`, который только отработал в на хосте
112 |
113 | Как видишь, контейнер думает, что корневой процесс это bash и у него PID = 1, но его реальный PID 2945.
114 |
115 | Я бы сравнил жизнь контейнера с параллельной вселенной, в которой уютно живется процессам
116 | контейнера, они не видят остального мира, но докер-хост видит его процессы полностью.
117 |
118 | Теперь представим, что мы отключили изоляцию PID. Что бы произошло? Процессы в контейнере
119 | приобрели такие же PID номера, что и в хостовой системе. Работа приложения в контейнере
120 | конечно будет нарушена. Получается, контейнер стал не таким изолированным, мы как бы
121 | совместили его реальность с хостовой.
122 |
123 | Давай зайдем еще дальше и отключим изоляцию UTS, которая отвечает за имя хоста. Как видишь
124 | мы еще больше совместили контейнер и низлежащую ОС.
125 |
126 | Теперь отключим изоляцию MNT и NET. Т.о. контейнер не сможет иметь свой собственный IP и
127 | собственную файловую систему. Теперь он полностью совпадает с ОС, он больше не изолирован.
128 |
129 | Как ты понимаешь, перегородки в этом общежитии контейнеров достаточно эфемерные, потому
130 | что и базовый докер-хост, и контейнеры совместно используют одни и те же системные ресурсы,
131 | такие как процессор и память.
132 |
133 | Ок, я надеюсь стало более понятнее, почему контейнер это совсем не виртуальная машина.
134 |
135 |
136 |
137 | Это подводит нас к вопросу сколько ресурсов будет выделено для хоста и контейнеров, а также
138 | как Docker управляет ресурсами и делится ими между контейнерами.
139 |
140 | По умолчанию нет ограничений на то, сколько ресурсов может использовать контейнер, и,
141 | следовательно, контейнер может в конечном итоге использовать все ресурсы на базовом хосте. Но
142 | есть способ ограничить объем ЦП или памяти, который может использовать контейнер. Docker
143 | использует контрольные группы (cgroups), чтобы ограничить количество аппаратных ресурсов,
144 | выделяемых каждому контейнеру. Это можно сделать, установив параметр --cpus в команде
145 | запуска контейнера.
146 |
147 | Например, `docker run --cpus=.5 nginx` позволит Docker использовать одномоментно не более 50%
148 | вычислительной мощности хоста.
149 |
150 | То же самое и с памятью: `docker run --memory=100m nginx`.
151 |
152 | Данная команда ограничит использование оперативной памяти контейнера лимитом в 100мб.
153 |
154 | Я привел лишь два примера, возможности Docker в части управления ресурсами достаточно гибкие.
155 | Если хочешь узнать больше, поищи в документации докера по слову limits или "resource constraints".
156 |
--------------------------------------------------------------------------------
/2_docker_commands/1_commands/1commands_review.md:
--------------------------------------------------------------------------------
1 | # Обзор команд
2 |
3 | ## Команды
4 |
5 | В этой лекции мы поговорим и посмотрим на команды.
6 |
7 | 1. Начнем с команды docker run
8 |
9 | ```docker
10 | docker run
11 | ```
12 |
13 | Как ты помнишь, образ - это шаблон приложения и его зависимостей собранных вместе.
14 | А контейнер - это экземпляр образа.
15 |
16 | docker run - используется для запуска контейнера из образа.
17 |
18 | ```docker
19 | docker run nginx
20 | ```
21 |
22 | Команда docker run nginx запустит экземпляр приложения nginx на твоем докер-хосте, если этот образ уже присутствует
23 | локально. Если его нет на хосте, то докер "сходит за ним" в докерхаб и спулит этот образ себе. Это потребуется сделать
24 | всего 1 раз. При следующих запусках этого контейнера докер будет использовать локальный образ.
25 |
26 | 2. Ты можешь посмотреть список запущенных контейнеров и основную информацию о них (о имени контейнера, его айди, статуса
27 | образа) с помощью команды docker ps
28 |
29 | ```docker
30 | docker ps
31 | ```
32 |
33 |
34 |
35 | Каждый контейнер получает случайным образом выбранный ID и случайное имя, если оно не было указано явно при создании.
36 |
37 | Весь список контейнеров, и запущенных и нет, показывает команда docker ps -a
38 |
39 | ```docker
40 | docker ps -a
41 | ```
42 |
43 |
44 |
45 | Как ты видишь, в системе 2 контейнера.
46 | Контейнер №1 работает, а №2 - нет.
47 |
48 | 3. Как остановить работающий контейнер?
49 |
50 | Используй docker stop вместе с id контейнера или его именем.
51 |
52 | ```docker
53 | docker stop
54 | ```
55 |
56 |
57 |
58 | Если ты не уверен в имени или id лучше для начала вызови docker ps
59 |
60 |
61 |
62 | Еще раз резюмируем:
63 |
64 | + docker ps - это запущенные контейнеры
65 | + docker ps -a - это все, которые есть на хосте (работающие и нет)
66 |
67 |
68 |
69 | Контейнер gracious_morse был создан для разовой работы. Он свою задачу выполнил, завершился и будущем мне уже не
70 | понадобится. Теперь он просто занимает место на диске.
71 |
72 | 4. Чтобы избавиться от ненужных контейнеров используй docker rm
73 |
74 | ```docker
75 | docker rm
76 | ```
77 |
78 | Эта команда полностью удаляет остановленные (stopped) или завершенные (exited) контейнеры.
79 | В случае успеха она вернет имя или id контейнера.
80 |
81 | ```docker
82 | docker rm gracious_morse
83 | ```
84 |
85 |
86 |
87 | Для проверки запустим docker ps и посмотримверно ли все удалилось.
88 |
89 |
90 |
91 | Как видишь, его больше нет в нашей системе.
92 |
93 | 5. А что со сканенным образом nginx, который докер скачал в начале?
94 |
95 | Он нам тоже не нужен. Мы не собираемся его больше использовать, нужно удалить этот образ. Но для начала давай посмотрим
96 | на список образов, представленных на нашем докер-хосте.
97 |
98 | Комадна docker images покажет все доступные на хосте образы, их id, теги и размер.
99 |
100 | ```docker
101 | docker images
102 | ```
103 |
104 |
105 |
106 | У нас представленно 5 образов локально: nginx, ubuntu, redis, weaveworks/scope, alpine.
107 | Чуть позже я расскажу про теги.
108 |
109 | 6. А сейчас сфокусируемся на удалении образов.
110 |
111 | Запустим команду
112 |
113 | ```docker
114 | docker rmi
115 | ```
116 |
117 | Помни!
118 | Перед тем как удалить образ тебе нужно убедиться, что контейнеры от этого образа не запущенны в системе.
119 | Тебе нужно остановить и удалить все зависимые от этого образа контейнеры прежде чем удалять сам образ.
120 |
121 | ```docker
122 | docker rmi redis
123 | ```
124 |
125 |
126 |
127 | 7. Ранее я запустил команду docker run и она скачала образ redis, поскольку не нашла его локально на хосте. А что, если
128 | мы просто хотим скачать образ и сохранить? Например для того, чтобы потом быстро запустить redis не ожидая пока его
129 | образ запуллиться из репозитория.
130 |
131 | В этом нам поможет команда docker pull
132 |
133 | ```docker
134 | docker pull redis
135 | ```
136 |
137 |
138 |
139 | Которая просто скачает образ, но не будет его запускать.
140 |
141 | Как видишь, найдя локально image, docker run не идет за ним в репозиторий.
142 |
143 |
144 |
145 | ## Особенности контейнеров
146 |
147 | Если мы запустим контейнер из образа Ubuntu при помощи команды
148 |
149 | ```docker
150 | docker run ubuntu
151 | ```
152 |
153 | Это запустит экземпляр ubuntu и немедленно выйдет из него.
154 |
155 |
156 |
157 | При просмотре работающих контейнеров мы не его не увидим
158 |
159 |
160 |
161 | Но если посмотреть всписок всех контейнеров, находящихся на хосте, включая остановленные, обнаружатся контейнеры с
162 | состоянием exited
163 |
164 |
165 |
166 | Это еще одно отличие от виртуальной машины, - контейнеры не предназначены для размещения операционных систем.
167 |
168 | Цель контейнера - выполнить работу и перестать потреблять ресурсы.
169 |
170 | Задания вроде анализа данных, расчета каких-то значений, размещения экземпляра БД или веб-сервера, - эти процессы хорошо
171 | подходят для контейнера.
172 |
173 | Как только задача завершается, т.е. основной процесс внутри контейнера завершается, контейнер останавливается.
174 | Становится exited.
175 |
176 | Получается, что контейнер живой, пока жив процесс с которым запускался контейнер.
177 |
178 | Это важно.
179 |
180 | Если веб-сервер или БД внутри контейнера скрашится или остановится, контейнер немедленно выйдет. Поэтому запустившийся
181 | контейнер с образом ubuntu моментально остановился. Потому что сама ОС является площадкой для запуска процессов. У нее
182 | не было процесса по умолчанию. Того огонька что поддерживало бы жизни контейнера.
183 |
184 | Тем не менее возможность запустить такой контейнер есть.
185 |
186 | Если в образе не запущено какое-либо приложение, как в случае с ubuntu, мы можем попросить докер запустить процесс с
187 | помощью команды docker run.
188 |
189 | Например команду сна с продолжительность 5 секунд:
190 |
191 | ```docker
192 | docker run ubuntu sleep 5
193 | ```
194 |
195 | При запуске контейнера в нем запуститься команда sleep, которая будет работать 5 секунд.
196 |
197 | Она и будет тем процессом в контейнере, ради которого он живет. Когда команда завершится, контейнер будет остановлен. А
198 | мы увидим на экране результат выполненной команды.
199 |
200 | ## Выполнить команду в контейнере
201 |
202 | Ок, мы научились запускать команду вместе с контейнером. А как сделать так, чтобы выполнить команду на работающем
203 | контейнере?
204 |
205 | Например, у меня выполняется контейнер с ubuntu. Когда я делаю docker ps -a, то вижу его статус Up.
206 |
207 |
208 |
209 | Внутри него выполняется команда sleep 500. Я хочу увидеть содержимое файла внутри контейнера. Как мне это сделать?
210 |
211 | Используем docker exec для выполнения команд на работающем контейнере:
212 |
213 | ```docker
214 | docker exec clever_morse cat /etc/hosts
215 | ```
216 |
217 |
218 |
219 | В данном случае, я вывел содержимое файла /etc/hosts, - это файла контейнера, а не ОС докер хоста.
220 |
221 | Если просто написать
222 |
223 | ```bash
224 | cat /etc/hosts
225 | ```
226 |
227 | То вывод будет другим, поскольку я обращусь к хостовой ОС, а не к контейнеру.
228 |
229 | ## Attach and detach
230 |
231 | Перед тем как перейти к практике, давай посмотрим еще на один момент.
232 |
233 | Для обучения у нас есть простое веб-приложение, его код есть на моем гитхабе, если тебе интересно.
234 |
235 | Его собранный образ лежит на докерхаб в rotorocloud/webapp - это приложение запускает небольшой веб-сервер, который
236 | доступен на порту 5000.
237 |
238 |
239 |
240 | После запуска команды
241 |
242 | ```docker
243 | docker run rotorocloud/webapp
244 | ```
245 |
246 | Приложение может быть развернуто в фоне или прикреплено к твоей консоли.
247 | Последнее значит, что стандартный output контейнера будет перенаправлен на твой терминал и ты будешь видеть весь вывод
248 | процесса веб-сервера на своем экране.
249 |
250 | Ты не сможешь никак взаимодействовать с консолью, пока она прикреплена к приложению, до тех пор пока контейнер не
251 | остановится.
252 |
253 | Для принудительной остановки использую комбинаюцию ctrl+c, - это остановит контейнер, приложение перестанет выполняться
254 | и ты попадешь обратно в приглошение своей ОС.
255 |
256 | Есть другой способ запустить докер-контейнер, использую detached mode.
257 |
258 | ```docker
259 | docker run -d rotorocloud/webapp
260 | ```
261 |
262 |
263 |
264 | Пишется как деш-ди. Это запустит контейнер в фоновом режиме и ты сразу же сможешь взаимодействовать со своей оболочкой.
265 |
266 | Контейнер продолжит свое выполнение. Чтобы проверить это ты можешь запустить docker ps
267 |
268 | В любой момент ты можешь прикрепить контейнер к консоли запустив команду docker attach с указанием id или имени
269 | контейнера
270 |
271 |
272 |
273 | Обрати внимание, что при использовании id, не обязательно писать длинную строку id. Достаточно указать первые несколько
274 | символов. Однако, если на хосте в данный момент есть дублирование первых символов каких-то id, то тебе придется указать
275 | больше символов. Например, пять или более. Чтобы докер однозначно понимал о каком id идет речь.
276 |
277 | В данный момент нам не интересна работа самого веб-сервера, нас интересует как запустить контейнер и как это выглядит из
278 | консоли.
279 |
280 | К работе приложения мы еще вернемся в следующих лекциях.
281 |
--------------------------------------------------------------------------------
/2_docker_commands/5_docker_run/docker_run.md:
--------------------------------------------------------------------------------
1 | # Особенности команды docker run
2 |
3 | Привет, и добро пожаловать на лекцию в которой мы подробнее рассмотрим особенности команды
4 | `docker run`. Это одна из наиболее часто используемых команд и у нее, наверное, больше всего
5 | параметров для запуска. Этот ряд особенностей тебе необходимо будет знать и уметь применять
6 | на практике, если ты хочешь, чтобы Docker облегчил твою жизнь. Мы попрактикуем это на
7 | лабораторной.
8 |
9 | Ок, мы уже умеем запускать контейнеризированный Redis командой `docker run redis`.
10 | В этом случае запустился Redis версии 6.0.9. Но что если мне нужна другая версия? Скажем, я хочу
11 | запустить Redis версии 5.0.
12 |
13 | Для этого надо указать версию через разделитель - (:) двоеточие после имени образа. Это
14 | называется tag. В этом случае Docker скачает образ Redis версии 5.0 и запустит его.
15 | Обрати внимание, если ты не указал тег, то Docker будет искать образ с тегом "latest". Тег latest
16 | обычно связывают с последней версией этого ПО и за его установку ответственны создатели
17 | продукта. Но как нам, как пользователям, найти информацию какие версии доступны у приложения
18 | и какая из них последняя?
19 |
20 | Поискать на https://hub.docker.com/. Найдем имя образа redis и список применимых к нему тегов, а
21 | также описания каждой версии для соответствующего тега. Каждая версия может иметь
22 | несколько коротких и длинных тегов, ссылающихся на нее. Как видишь версия 6.0.9 также еще и
23 | имеет тег latest.
24 |
25 | Теперь давай поговорим о вводе. Для пояснения у меня есть маленькое приложение, оно доступно
26 | на докерхабе, если захочешь запустить. Итак, на первом шаге у меня был простой шелл-скрипт,
27 | который при запуске спрашивал имя, а после ввода писал на экране приветствие и те данные,
28 | которые ему передали при вводе.
29 |
30 |
31 |
32 | Я произведу некоторые манипуляции, о которых поговорим чуть позже, и сделаю из этого скрипта
33 | докеризированное приложение. При его запуске таким образом: `docker run rotorocloud/prompt-docker` мы не получим
34 | приглашение к вводу. Приложение напишет только то,
35 | что жестко прописано в скрипте, т.к. оно не получило никаких данных. Это произошло потому, что
36 | по умолчанию докер-контейнеры не слушают стандартный ввод. Даже с присоединенной консолью
37 | он не сможет прочитать введенные тобой данные. У него нет терминала для чтения ввода, он
38 | работает в неинтерактивном режиме.
39 |
40 | Давай добавим возможность ввода, подключив терминал, откуда мы эти данные введем.
41 | Чтобы это сделать используй параметр -t (-t означает использование псевдотерминала). В этот раз
42 | приложение сразу не вышло. Я получил приглашение на ввод данных, но что-то идет не так - когда
43 | пытаюсь ввести имя и нажать ввод ничего не происходит. Не работают даже клавиши,
44 | останавливающие приложение. Что же произошло?
45 |
46 | ОС внутри контейнера видит мой терминал, а команда, выполняющаяся в данный момент ждет с
47 | него данные. Проблема в том, что мы не связали стандартный ввод (stdin) своего хоста с stdin
48 | контейнера. И контейнер изолирован в части получения данных из стандартного ввода. Команда
49 | останется в вечной петле ожидания, пока мы не убьем контейнер.
50 |
51 | Чтобы контейнер стал принимать данные на свой стандартный ввод с терминала или какого-либо
52 | pipe используй параметр -i. Параметр -i включает интерактивный режим, и когда мы вводим свои
53 | данные, они успешно поступают на ввод нашего контейнера. Теперь мы можем ввести данные с
54 | клавиатуры, а команда их получит, и мы увидим ожидаемый вывод.
55 | Итак, комбинация -it дала нам возможность подключится и взаимодействовать с контейнером в
56 | интерактивном режиме. Хочешь подключиться к контейнеру - будь из IT, легко запомнить :)
57 |
58 | Параметр -it нужен для непосредственного подключения человека, потому что терминал дает
59 | возможность контейнеру получить некоторые управляющие команды, а также обеспечивает
60 | дополнительные возможности вывода на консоль пользователя. В случае с автоматизацией
61 | обычно достаточно -i.
62 |
63 | Вот случай автоматического pipe, команда:
64 |
65 | ```docker
66 | echo "Rotoro" | docker run -i rotorocloud/simple-prompt-docker
67 | ```
68 |
69 | Команда echo и контейнер в пайпе сами договорятся без всяких терминалов
70 |
71 |
72 |
73 | Самое время разобраться с публикацией портов или как их еще называют пробросом портов в
74 | контейнер. Давай вернемся к примеру с нашим веб-сервером на 5000 порту, с которым мы
75 | познакомились в предыдущей главе. Запустим его на нашем докер-хосте. Как ты помнишь, хост, на
76 | который установлен Docker в части запуска контейнеров, называется Docker host или Docker engine.
77 |
78 | Когда мы запускаем контейнеризированное веб-приложение, оно начинает работать, и мы видим,
79 | что сервер запустился. Но как нам дать доступ пользователям к этому приложению?
80 |
81 | Как видишь, мое приложение слушает на порту 5000, я могу получить доступ через этот порт. Но
82 | какой IP мне использовать в своем браузере?
83 |
84 | Тут есть два варианта.
85 |
86 | Первый использовать IP докер-контейнера, т.к. у каждого контейнер есть свой собственный адрес,
87 | каждый докер-контейнер получает IP присвоенный по умолчанию. В данном случае 172.17.0.2. Но
88 | помни, что этот адрес внутренний и будет доступным только внутри докер-хоста, где контейнер
89 | выполняется. В общем, если ты запустишь на своем докер-хосте браузер, введешь в нем
90 | http://172.17.0.2:5000 и получишь доступ. Но пользоваться этим сервисом смогут только
91 | внутренние пользователи этого хоста. Т.к. это внутренний IP внешние пользователи не смогут
92 | использовать этот URL.
93 |
94 | Для внешних запросов мы могли бы использовать IP, по которому внешние пользователи ходят на
95 | наш хост, 10.0.0.13 в нашем случае. Но для того, чтобы это заработало, мы должны сопоставить
96 | порт внутри контейнера со свободным портом на докер-хосте. Допустим, я хочу, чтобы
97 | пользователи получили доступ к моему приложению на порту 80 нашего докер-хоста. Тогда мне
98 | нужно сопоставить порт 80 localhost с портом 5000 в контейнере Docker.
99 |
100 | Для этого используй параметр -p в команде `docker run`. И пользователи смогут получить доступ к
101 | приложению по URL http://10.0.0.13:80. Весь трафик, полученный на этот порт 80 будет
102 | маршрутизирован на порт 5000 внутри контейнера. Таким манером ты можешь запускать много
103 | экземпляров разных приложений и сопоставлять их различным портам на докер-хосте.
104 |
105 | Например, я развернул экземпляр mysql, который запустил БД и начал слушать на дефолтном порту
106 | mysql 3306. Также я запустил еще один инстанс базы, смаппив его порт 3306 на порт 8306 хоста.
107 | Итак, ты можешь запустить столько приложений, сколько тебе нужно и пробросить столько
108 | портов, сколько тебе требуется. Разумеется есть ограничение в том, что ты не можешь назначить
109 | один порт докер-хоста несколько раз.
110 |
111 | Мы еще вернемся к пробросу портов и сетевом взаимодействии в лекции о сетях в Docker. А сейчас
112 | давай познакомимся с тем, как нам хранить постоянные данные при использовании контейнеров.
113 |
114 |
115 |
116 | Допустим у нас запущен контейнер с mysql. Когда базы и таблицы будут созданы, физически они
117 | будут сохранены по по пути /var/lib/mysql в докер-контейнере. Запомни, что контейнер имеет свою
118 | собственную изолированную файловую систему и любые изменения происходят только в ней, они
119 | не имеют отношения к файловой системе хоста. Теперь мы зальем большой дамп данных в эту
120 | базу. Что произойдет если мы удалим этот mysql-контейнер?
121 |
122 | Как только произойдет удаление, мы потеряем все данные. Это связано со слоистой структурой
123 | контейнеров, о чем мы поговорим позже в этом курсе. Как же хранить постоянные данные в
124 | контейнерах?
125 |
126 | С помощью специальной директории, размещенной на докер-хосте, данные в которой не будут
127 | относится непосредственно к контейнеру, а будут подключены как бы извне. Как будто внешний
128 | жесткий диск. Нам потребуется связать две директории: одну на хосте, а вторую в контейнере. В
129 | этом случае я создал директорию /opt/datadir и пробросил ее в контейнер по размещению
130 | /var/lib/mysql.
131 |
132 | Для создания связи используется параметр -v, а далее пишется путь до директории на хосте, потом
133 | двоеточие-разделитель и папка внутри контейнера. Сначала откуда - с хоста, потом куда - в
134 | контейнер. Легко запомнить.
135 |
136 | Таким образом, при запуске докер-контейнер неявно монтирует внешнюю директорию в свою
137 | внутреннюю. Теперь все данные спокойно лежат во внешнем томе в директории /opt/datadir
138 | докер-хоста и не зависят от жизни контейнера. Они останутся там, даже если контейнер будет
139 | удален.
140 |
141 |
142 |
143 | Команда `docker ps` хорошо подходит для быстрого сбора основные деталей о контейнерах в нашей
144 | системе. Таких как имена, ID и т.д. Но периодически нам будет требоваться развернутая
145 | информация о каком-то контейнере. В подобных случаях нас выручит команда `docker inspect`, она
146 | запускается с именем или ID контейнера.
147 |
148 | Она вернет нам детальную картину этого контейнера в JSON формате. Его состояние, что
149 | смонтировано, как сконфигурировано, настройка сети и т.д. Не забудь про нее, когда тебе нужно
150 | будет узнать детали запущенного и забытого кем-то контейнера или в похожей задаче.
151 |
152 |
153 |
154 | И наконец траблешутинг. Когда что-то идет не так, мы смотрим логи. Как их смотреть в
155 | контейнерах?
156 |
157 | С помощью команды `docker logs`. Чтобы посмотреть эту команду давай запустим наше
158 | веб-приложение в фоновом режиме используя параметр -d.
159 | `docker run -d rotorocloud/webapp` запустит его в detached mode.
160 |
161 | Теперь запустим команду `docker logs`, а дальше имя контейнера или его ID. Мы видим журнал,
162 | сформированный из stdout того контейнера.
163 |
164 | В мире разработки контейниризированных приложений часто практикуется не хранить логи в
165 | файлах, а передавать информацию на стандартный вывод, где ее собирает агент мониторинга. Об
166 | этом мы подробно говорим в курсе разработчика приложений для Kubernetes.
167 |
168 | > docker run имя:версия - запустить контейнер нужной версии
169 | >
170 | > docker run -it имя команда - запустить контейнер и вывести вывод в терминал
171 | >
172 | > -i - связать стандартный ввод хоста со стандартным вводом контейнера
173 | >
174 | > -t - связать стандартный вывод хоста со стандартным выводом контейнера
175 | >
176 | > echo 'qwe' | docker run -i имя - передать на ввод контейнеру строку qwe
177 | >
178 | > docker run -p 80:5000 имя - сопоставить порт 80 хоста порту 5000 в контейнере
179 | >
180 | > docker run -v /opt/datadir/:/var/lib/mysql имя - смонтировать каталог /opt/datadir/ хоста в каталог /var/lib/mysql в
181 | > контейнере
182 | >
183 | > docker inspect имя - детальная информация о контейнере
184 | >
185 | > docker logs имя - вывести стандартный вывод контейнера
186 |
187 |
188 |
--------------------------------------------------------------------------------
/5_docker_storage/5_3_docker_storage/docker_storage.md:
--------------------------------------------------------------------------------
1 | # Хранилище
2 |
3 | Привет и добро пожаловать на лекцию. В этой лекции мы изучаем продвинутые концепции Docker,
4 | а именно поговорим драйверах хранилища Docker и файловых системах. Мы посмотрим, где и как
5 | Docker хранит данные, и как он управляет файловыми системами контейнеров.
6 |
7 |
8 |
9 | Давай начнем с того, как Docker хранит данные в локальной файловой системе.
10 |
11 | Когда мы устанавливаем Docker в систему, он создает некоторую структуру папок в каталоге
12 | /var/lib/docker. Там находится несколько папок, с названиями overlay2, containers, image, volumes и
13 | т. д. Здесь Docker по умолчанию хранит все свои данные. Когда я говорю «данные», я имею в виду
14 | файлы, связанные с образами и контейнерами, запущенными на этом докер-хосте. Например, все
15 | файлы, относящиеся к контейнерам, хранятся в папке containers, а файлы, связанные с образами,
16 | хранятся в папке image. Любые тома, созданные для докер-контейнеров, создаются в папке
17 | volumes.
18 |
19 | Что ж, пока не беспокойся об этом. Мы вернемся к этому чуть позже. А пока давай просто
20 | разберемся, где Docker хранит свои файлы и в каком формате. Итак, как именно Docker хранит
21 | файлы образа и контейнера?
22 |
23 |
24 |
25 | Чтобы это хорошо понять, нужно вникнуть в многоуровневую или слоеную архитектуру Docker.
26 | Давай быстро вспомним то, что мы узнали об этом.
27 |
28 | Когда Docker создает образы, он создает их в многоуровневой архитектуре. Каждая строка
29 | инструкции в Dockerfile создает новый слой в докер-образе с фиксацией изменений от
30 | предыдущего уровня.
31 |
32 | Например, первый уровень - это базовая операционная система Ubuntu, за которой следует вторая
33 | инструкция, которая создает второй слой, который устанавливает все пакеты APT. Затем третья
34 | инструкция создает третий уровень, который занимается пакетами python, за которым следует
35 | четвертый уровень, который копирует исходный код. И, наконец, пятый слой, который обновляет
36 | точку входа образа.
37 |
38 | Поскольку каждый слой сохраняет только изменения из предыдущего, это отражается и на
39 | размере. Если мы посмотрим на базовый размер образа, он имеет размер около 80 мегабайт.
40 | Пакеты apt, которые были установлены составляют около 450 МБ, а оставшиеся слои малы, чтобы
41 | понять преимущества этой многоуровневой архитектуры.
42 |
43 | Теперь посмотрим второе приложение, в котором есть другой Dockerfile, но он очень похож на наше
44 | первое приложение. В нем используется тот же базовый образ, что и раньше, это ubuntu и оно
45 | использует те же зависимости Python и Flask, но имеет в себе другой исходный код для создания
46 | образа и также другую точку входа.
47 |
48 | Когда я запускаю команду `docker build`, чтобы создать новый образ для этого приложения, первые
49 | три уровня обоих приложений будут одинаковы и Docker не будет создавать эти первые три уровня.
50 | Вместо этого он повторно применит одинаковые, уже созданные первые три слоя, которые он
51 | сделал для первого приложения. Их он возьмет из кэша, в который ложит все слои, когда-либо
52 | собранные на докер-хосте.
53 |
54 | Далее, он создаст только последние два слоя с новым исходным кодом и новой точкой входа.
55 | Вновь собранные слои он также положит в кэш. Таким образом Docker создает образы быстрее и
56 | эффективно экономит дисковое пространство.
57 |
58 | Это также применимо, если требуется обновить код своего приложения. Всякий раз, когда нужно
59 | обновить исходный код, например app.py, как в нашем случае, Docker просто повторно использует
60 | все предыдущие слои из кэша и быстро перестроит образ приложения, обновив слои с исходным
61 | кодом и следующие за ним. Таким образом, это сохранит нам много времени во время перестроек
62 | и обновлений образов.
63 |
64 |
65 |
66 | Для наглядности, давай разместим слои снизу вверх, чтобы мы могли все это лучше понять.
67 |
68 | Внизу у нас есть базовый уровень ubuntu, затем пакеты, затем зависимости, а затем исходный код
69 | приложения и точка входа. Все эти слои создаются, когда мы запускаем команду `docker build`.
70 | Формируется окончательный образ Docker, состоящий из этих слоев. После завершения создания
71 | образа мы не можем изменять содержимое этих слоев, они доступны только для чтения, а
72 | изменить их возможно только через запуск новой сборки.
73 |
74 | Когда мы запускаем контейнер, основанный на этом образе при помощи команды docker run,
75 | Docker создает контейнер на основе этих слоев, а далее создает новый слой поверх слоев образа, с
76 | которого можно не только читать, но и в который можно писать. Слой с возможностью записи
77 | используется для хранения и изменения данных, созданных контейнером. Таких данных, как логи,
78 | временные файлы и прочие вещи, необходимые для работы приложения. В него также попадает
79 | любой файл, измененный пользователем в этом контейнере. Срок жизни этого слоя ограничен
80 | временем, пока жив контейнер. Когда контейнер разрушается, этот слой со всеми сохраненными в
81 | нем изменениями уничтожается.
82 |
83 |
84 |
85 | Помни, что одни и те же слои образа делятся между всеми контейнерами, запущенными с
86 | использованием этого образа. Скажем, я зайду в созданный контейнер и создам там новый файл с
87 | именем temp.txt. Этот файл будет создан на уровне контейнера, который доступен для чтения и
88 | записи.
89 |
90 | Как мы только что сказали, что файлы в слоях образа доступны только для чтения, что означает,
91 | что мы не можем ничего редактировать в этих слоях. Теперь давай возьмем пример кода нашего
92 | приложения, поскольку мы запекли наш код в образ. Код является частью одного их слоев образа,
93 | и, следовательно он будет доступен только для чтения после запуска контейнера. Что, если я хочу
94 | изменить исходный код, скажем для какого-то теста?
95 |
96 | Вспоминаем, что один и тот же слой образа может использоваться несколькими контейнерами,
97 | созданными из этого образа. Значит ли это, что я не могу изменить этот файл внутри контейнера?
98 |
99 | Нет, я все еще могу изменить этот файл, но прежде, чем я сохраню измененный файл, Docker
100 | автоматически создает копию файла на уровне чтения и записи, и затем я буду изменять и работать
101 | уже с другой версией файла, которая уже будет находится в другом слое - в слое контейнера, слое
102 | чтения и записи. Все будущие изменения будут внесены в эту копию файла на уровне
103 | чтения-записи. Это называется механизмом копирования при записи (copy-on-write).
104 |
105 | Слои образа доступны только для чтения, это означает, что файлы в этих слоях не будут изменены
106 | на самом деле, образ будет оставаться неизменным все время, пока ты не перестроишь его с
107 | помощью команды `docker build`.
108 |
109 | Итак, пока файлы не изменились, их не существует в слое контейнера. Они все где-то в слоях
110 | образа. Что происходит, когда мы избавляемся от контейнера?
111 |
112 | Все данные, которые хранились на уровне контейнера, также удаляются. Изменения, которые мы
113 | внесли в app.py и новый временный файл, который мы создали, также будут удалены. А что, если
114 | мы хотим сохранить эти данные?
115 |
116 |
117 |
118 | Например, мы работали с базой данных и хотели бы сохранить данные, созданные контейнером.
119 | Для этих целей мы можем добавить в контейнер постоянный том (volume).
120 |
121 | Чтобы сделать это, сначала создадим том с помощью команды `docker volume create`.
122 |
123 | Когда мы запускаем команду `docker volume create data_volume`, она создает папку с именем
124 | data_volume в каталоге /var/lib/docker/volumes. Затем, когда я запускаю докер-контейнер с
125 | помощью команды `docker run`, я могу смонтировать этот том внутрь контейнера для чтения и
126 | записи, используя опцию -v, как ты видишь на экране.
127 |
128 | Я указал в `docker run -v` и имя моего вновь созданного тома, за которым идет двоеточие и
129 | местоположение внутри моего контейнера, которым является местоположением по умолчанию,
130 | где MySQL хранит данные, т.е. /var/lib/mysql. Далее указал имя образа.
131 |
132 | Теперь Docker создаст новый контейнер и смонтирует созданный ранее том в папку /var/lib/mysql
133 | внутри контейнера, и все данные, записанные базой данных, фактически будут хранится в томе,
134 | созданном на докер-хосте. Даже если контейнер разрушится, данные остаются целыми. А что, если
135 | мы не запускали команду `docker volume create` для создания тома, прежде чем сделали `docker
136 | run`?
137 |
138 | Например, я запускаю команду `docker run` для создания нового экземпляра контейнера mysql с
139 | параметром монтирования тома data_volume_2, но том я еще не создал. В таком случае Docker
140 | автоматически создаст том с именем data_volume_2 и подключит его к контейнеру. Мы можем
141 | найти все эти созданные тома, если просмотрим содержимое папки /var/lib/docker/volume. Это
142 | называется volume mounting, поскольку мы монтируем том, созданный Docker в папке
143 | /var/lib/docker/volume. Но что, если мы уже разместили данные в другом месте и не хотим их
144 | переносить в папку /var/lib/docker/volume?
145 |
146 | Например, у нас есть директория в хранилище докер-хоста в размещении /data, и мы хотели бы
147 | хранить данные базы данных в качестве тома в этой папке, а не в директории томов docker по
148 | умолчанию. В этом случае мы также запустим контейнер с помощью команды `docker run -v`. Но в
149 | этом случае мы предоставим полный путь в папку, которую хотим смонтировать. Это /data/mysql, и
150 | Docker создаст контейнер и подключит папку к контейнеру. Это называется bind mounting.
151 |
152 | Таким образом, существует два типа монтирования: монтирование тома и монтирование с
153 | привязкой. Volume mounting монтирует том из каталога томов, а bind mounting монтирует каталог из
154 | любого места на докер-хосте.
155 |
156 | И напоследок отмечу, что использование -v - это старый стиль. Новый способ - использовать опцию
157 | --mount. Это считается более предпочтительным способом, поскольку он более подробный, хотя на
158 | практике я его встречаю реже. В этом случае, мы должны указать каждый параметр в формате
159 | «ключ равно значение». Например, предыдущая команда может быть записана с параметром
160 | --mount, и далее указав опции source и target. Type этом случае - bind, источник - это
161 | местоположение на моем хосте, а цель - это местоположение в моем контейнере.
162 |
163 |
164 |
165 | Ок, а кто несет ответственность за выполнение всех этих операций. Сохранение многоуровневой
166 | архитектуры. Создание слоя с возможностью записи, перемещение файлов между слоями для
167 | возможности копирования и записи и т. д.
168 |
169 | Это storage drivers. Таким образом, Docker использует драйверы хранилища для обеспечения
170 | многоуровневой архитектуры. Некоторые из распространенных драйверов хранения: AUFS, BTRFS,
171 | ZFS, device-mapper, overlay и overlay 2, fuse overlayfs. Некоторые из них широко используются,
172 | некоторые уже устарели, но могут встретиться в каких-то легаси нагрузках.
173 |
174 | Выбор драйвера хранилища зависит от используемой ОС. Например, у Ubuntu.
175 | Драйвер хранилища по умолчанию для нее - это overlay2. Но до 18 версии Docker это был aufs, и он
176 | был недоступен в таких операционных системах, таких как Fedora или CentOS, и в них приходилось
177 | использовать device-mapper.
178 |
179 | Docker сам постарается выбрать лучший драйвер хранилища, который доступен в конкретной
180 | операционной системе. Но это не всегда работает хорошо. В случае проблем нужно настраивать
181 | руками, изучив соответствующие issues по конкретной ОС и ее ядру. Где-то до 18 года это было
182 | серьезной проблемой, с появлением overlay2 дела стали обстоять гораздо лучше.
183 |
184 | Различные драйверы хранилища также обеспечивают разные характеристики производительности
185 | и стабильности, поэтому ты можешь выбрать тот, который соответствует потребностям твоего
186 | приложения и соответствии требования твоей организации. Если хочешь быть осведомленным о
187 | каком-либо из этих драйверов хранения, начни с документации Docker, а далее погрузись в десятки
188 | issues на гитхаб докера.
189 |
--------------------------------------------------------------------------------
/1_introduction/1docker_review.md:
--------------------------------------------------------------------------------
1 | # Для чего нужны контейнеры
2 |
3 | ## Как я познакомился с докером.
4 |
5 | В одном из моих педыдущий проектов было требование настроить сквозной стек, включающий различные технологии:
6 |
7 | + веб-сервер, использующий node js
8 | + БД, такую как mongoDB
9 | + система обмена сообщениями Redis
10 | + оркестрация с помощью Ansible
11 |
12 | Из-за того, что компоненты были разнородные мы столкнулись с множеством проблем при разработке и поддержке этого
13 | приложения.
14 |
15 | Во-первых, их совместимость с базовой операционной системой. Мы должны были обеспечить чтобы все эти сервисы были
16 | совместимы с версиями ОС, которую мы планировали использовать. Получалось что некоторые версии этих компонентов были
17 | несовместимы с ОС. Нам приходилось останавливаться и находить другую ОС совместимую со всеми этими службами.
18 |
19 | Во-вторых, нам нужно было быть уверенными в совместимости сервисов и библиотек с зависомостями ОС. У нас были проблемы,
20 | когда для одной службы нужна была одна версия зависимой библиотеки, а для другой службы - другая.
21 |
22 | Со временем архитектура нашего приложения менялась. Нам пришлось обновить компоненты до более новой версии. Поменять БД
23 | и т.д. Каждый раз, когда что-то менялось, нам приходилось проходить один и тот же процесс проверки совместимости между
24 | этими различными компонентами и базовой инфраструктурой.
25 |
26 | Эта проблема с матрицой совместимости обычно называется "матрицой из ада".
27 |
28 | Далее каждый раз, когда у нас появлялся новый разработчик, нам было действительно сложно создать новую среду. Новым
29 | разработчикам приходилось следовать большому набору инструкций и запускать сотни команд, чтобы наконец настроить свою
30 | среду. Они должны были убедиться, что используют правильную ОС, правильную версию каждой из компонент. И каждый
31 | разработчик должен был настраивать все это каждый раз самостоятельно.
32 |
33 | У нас также были разные среды для разработки, тестирования и продакшена.
34 |
35 | Одному разработчику было удобно использовать одну ОС, другим - другую. Поэтому мы не могли гарантировать, что созданное
36 | приложение будет работать одинаково в разных средах.
37 |
38 | И так все это значительно усложнило нам жизнь в разработке, создании и доставке приложения.
39 |
40 | Нам нужно было что-то, что могло помочь нам в решении проблем с совместимостью. Что-то что позволит нам изменять или
41 | заменять эти компоненты не затрагивая другие компоненты и даже изменять базовые ОС по мере необходимости.
42 |
43 | И этот поиск привел меня к Docker.
44 | В докер я мог запускать каждый компонент отдельно с своими собственными библиотеками и зависимостями от одной и той же
45 | виртуальной машины и ОС. Все упаковывалось в отдельное окружение - контейнер.
46 |
47 | Нам нужно было один раз собрать конфигурацию докер и теперь все наши разработчики могли начать работу с простой команды
48 | запуска докера.
49 |
50 | Не зависимо от того, какую ОС они используют все, что им нужно было сделать - это убедиться, что и их системах
51 | установлен докер.
52 |
53 | ## Так что же такое контейнер?
54 |
55 | Контейнер - это полностью изолированные среды.
56 |
57 | В них свои процессы и службы. Собственные сетевые интерфейсы, собстевнные средства монтирования.
58 |
59 | Это похоже на виртуальные машины. За исключением того, что все они используют одно ядро ОС.
60 |
61 | Мы немного рассмотрим, что это значит.
62 |
63 | Также важно отметить, что контейнеры не новость в докер. Контейнеры существовали около 10 лет.
64 |
65 | Рассмотрим некоторые из типов контейнера.
66 |
67 | Докер использует контейнеры lxc, настроить эти контейнерные среды сложно поскольку они очень низкого уровня.
68 |
69 | Именно здесь докер предлагает инструменты более высокого уровня с несколькими мощными функциями, которые делают его
70 | действительно легким для таких конечных пользователей как мы.
71 |
72 | Чтобы понять как работает докер давай сначала вернемся к некоторым основным концепциям ОС.
73 |
74 | Если ты посмотришь на такие ОС как убунта, федора или центос, все они состоят из двух вещей: ядро ОС и ПО.
75 | Ядро ОС отвечает за взаимодействие с базовым оборудованием. В то время как ядро ОС остается тем же, в данном случае
76 | Линукс, слой ПО, расположенный выше, отличается для разных ОС. Это ПО может состоять из интерфейсов пользователя,
77 | драйверов, компиляторов, файловых менеджеров, инструментов разработчика и т.д.
78 |
79 | В итоге у нас есть общее ядро Линукс, используемое во всех ОС, и некоторое настраиваемое ПО, которое отличает одну ОС от
80 | другой.
81 |
82 | Ранее мы говорили, что контейнеры докер совместно используют базовое ядро. Что на самом деле означает совместное
83 | использование ядра?
84 |
85 | Допустим у нас есть система с ОС убунту с установленным на ней докер. Докер может запускать поверх себя любую версию ОС,
86 | если все они основаны на одном ядре. В данном случае Линукс. Если базовой ОС является убунту, докер может запускать
87 | контейнер на основе другого дистрибутива, например дебиан, федора, сьюс или центос.
88 |
89 | В каждом докер контейнере есть только дополнительное ПО, которое делает ОС разными. И докер использует базовое ядро
90 | своего хоста, которое работает со всеми вышеперечисленными ОС.
91 |
92 | А какая ОС не имеет такого же ядра? Windows. И поэтому ты не сможешь запустить контейнер на базе Виндовс на докер хосте
93 | с ОС Линукс. Для этого нам потребуется докер на сервере Виндовс.
94 |
95 | Ты спросишь: разве это не недостаток? Невозможно запустить другое ядро в ОС. Ответ: нет.
96 | Потому что в отличие от гипервизоров, докер не предназначен для виртуализации и запуска различных ОС и ядер на одном
97 | оборудовании.
98 |
99 | Основное назначение докер - контейнеризация приложений, а также их отправка и запуск.
100 |
101 | Это подводит нас к различиям между виртуальными машинами и контейнерами.
102 | Вещи, которыми занимаются те, кто занимается виртуализацией.
103 |
104 | ## Различиям между виртуальными машинами и контейнерами
105 |
106 | | VM | Docker |
107 | |-------------------------------------------------------------------------------|------------------------------------------------|
108 | | Виртуальная машина: приложение, библиотеки, зависимости, операционная система | Контейнер: приложение, библиотека, зависимости |
109 | | Гипервизор | Docker |
110 | | Операционная система | Операционная система |
111 | | Аппаратная инфраструктура | Аппаратная инфраструктура |
112 |
113 | Как видишь справа в случае с докером у нас есть базовая аппаратная инфраструктура, затем ОС и докер, устновленный на ОС.
114 | Докер может управлять контейнерами, которые работают с библиотеками и зависимостями сами в одиночку.
115 |
116 | В случае виртуальной машины, у нас есть ОС на базовом оборудовании. Затем гипервизор такой как esx или какая-то другая
117 | виртуализация. А затем виртуальная машина.
118 |
119 | Как видишь у каждой виртуальной машины внутри своя ОС, толстый слой
120 | зависимостей, а затем приложение. Эти накладные расходы приводят к более высокому использованию вычислительных ресурсов.
121 | Поскольку приходится крутить несколько виртуальных ОС с их ядрами.
122 |
123 | Также виртуальные машины потребляют больше дискового пространства поскольку каждая виртуальная машина тяжелая и обычно
124 | имеет размер в гигабайтах. Тогда как контейнеры докер легковесны и обычно имеют размер в мегабайтах.
125 |
126 | Это позволяет докер контейнерам загружаться быстрее, обычно за считанные секунды. Тогда как виртуальные машины грузятся
127 | по несколько минут, так как для этого требуется загрузка всей ОС.
128 |
129 | Также важно отметить, что докер имеет меньшую изоляцию, поскольку больше ресурсов используется совместно между
130 | контейнерами, например ядро. Тогда как виртуальные машины полностью изолированы друг от друга.
131 |
132 | В случае виртуальной машины у нас могут быть разные типы ОС такие как Линукс или Виндовс на основе одного и того же
133 | гипервизора. Тогда как на докер хосте это невозможно.
134 |
135 | Так что же выбрать: контейнеры или виртуальные машины?
136 |
137 | Я скажу так: выбери лучшее от обеих технологий.
138 | Ты можешь работать с контейнерами на виртуальных хостах докера. Виртуализация даст тебе возможность легковводить,
139 | выводить из эксплуатации или перемещать большое количество докер хостов. А контейнеризация - быстро масштабироваться и
140 | легко обновляться.
141 |
142 | С таким подходом тебе не нужно создавать определенную виртуальную машину под конкретное приложение. Теперь это задача
143 | виртуальной машины - запускать контейнеры и делать это хорошо. И эта эластичность и гибкость отлично подходит к облачным
144 | вычислениям.
145 |
146 | В облаке сегодня ты можешь иметь тысячи контейнеров на сотне докер хостов, а завтра легко вырасти или уменьшится при
147 | необходимости.
148 |
149 | Это были ключевые различия между ними.
150 |
151 | ## Как сделать все это руками?
152 |
153 | На сегодняшний день доступно много контейнерных версий приложений.
154 | Продукты большинства организаций хранятся в контейнерах и могут быть получены из общедоступного docker registry с
155 | названием dockerhub.
156 |
157 | Например, ты можешь найти образ наиболее распространенных ОС, БД и других сервисов и инструментов.
158 |
159 | Как только ты определился с образом, тебе нужно установить докер на свой хост.
160 |
161 | Для запуска приложения просто напиши команду docker run с именем образа.
162 |
163 | ```shell
164 | docker run ansible
165 | ```
166 |
167 | В этом случае запуск команды docker run ansible запустит экземпляр ansible на докер хосте.
168 |
169 | Точно также запускаются экземпляры mongodb, redis, nodejs с помощью команды docker run.
170 |
171 | Когда запускаешь экземпляр nodejs просто укажи расположение репозитория нода.
172 |
173 | ```shell
174 | docker run mongodb
175 | ```
176 |
177 | ```shell
178 | docker run redis
179 | ```
180 |
181 | ```shell
182 | docker run node
183 | ```
184 |
185 | Если тебе нужно несколько экземпляров веб-службы, просто создай требуемое количество экземпляров и настрой какой-либо
186 | балансировщик нагрузки на входе.
187 |
188 | В случае отказа одного из экземпляров, просто уничтож этот экземпляр и зупусти новый инстанс.
189 |
190 | Существуют и другие решения для обработки таких случаев, их мы рассмотрим позже в ходе этого курса.
191 |
192 | ## Разница мужду образами и контейнерами.
193 |
194 | Мы говорили об образах и контейнерах. Давай поймем разницу между ними.
195 |
196 | Образ - это пакет или шаблон. Анологичный шаблону виртуальной машины, с которыми ты мб работал в среде виртуализации. Он
197 | используется для создания одного или нескольких контейнеров. Докер запускает экземпляр образов, которые изолированы,
198 | имеют свои собственные среды и процессы.
199 |
200 | Как мы видели раньше, многи продукты уже докерезированы. Если ты не можешь найти то, что тебе нужно, ты можешь создать
201 | образ самостоятельно. Отправить его в репозиторий в докерхаб и сделать его доступным для всех.
202 |
203 | Если посмотреть традиционно, то приложение разрабатывают разработчики, потом передают апстриму для развертывания и
204 | управления в производственных средах. Они делают это предоставляя набор инструкций таких как информация о том, как
205 | должны быть устновлены хосты, какие предварительные условия должны быть соблюдены и как должны быть настроены
206 | зависимости.
207 |
208 | Команда ops использует это руководство для настройки приложения. Поскольку команда ops не разрабатывала приложение
209 | самостоятельно, они борются с его настройкой. Когда они сталкиваются с проблемой, то начинают дергать разработчиков. С
210 | докер основная часть работы, связанная с понятием инфраструктуры, теперь находится в руках разработчиков в виде
211 | докерфайла. Руководство, ранее созданное разработчиками для настройки инфраструктуры, теперь просто ложится в докер файл
212 | для создания образа приложения - этот образ теперь будет работать на любой контейнер на платформе и гарантированно будет
213 | работать везде одинаково. Таким образом, команда оперирования теперь может просто использовать образ для развертывания
214 | приложения.
215 |
216 | Поскольку образ работал, когда разработчик создал его, а другие операции не изменяют образ, он продолжит работать таким
217 | же образом при развертывании в производственной среде.
218 |
219 |
220 |
221 |
222 |
--------------------------------------------------------------------------------
/4_docker-compose/4_1_docker-compose/docker-compose.md:
--------------------------------------------------------------------------------
1 | # Docker-compose
2 |
3 | Привет и добро пожаловать на лекцию о Docker Compose. Дальше в лекции мы будем работать с
4 | конфигурациями в Yaml-файлах. Поэтому важно, чтобы ты чувствовал себя комфортно с yaml. Для
5 | новичков в yaml в секции приложений в конце курса есть материалы, которые помогут тебе быстро
6 | освоиться в этом формате представления данных.
7 |
8 |
9 |
10 | Давай быстро резюмируем несколько вещей. Мы знаем, как построить образ, как отправить его на
11 | хранение и как запустить докер-контейнер с помощью команды `docker run`. Так, а если теперь нам
12 | нужно настроить сложное приложение с несколькими компонентами, как нам поступить?
13 |
14 | Можно написать скрипт с несколькими командами `docker run`. Но лучший способ сделать это -
15 | использовать Docker Compose. Мы могли бы создать файл конфигурации в формате YAML под
16 | названием docker-compose.yml и положить туда все различные службы и прописать параметры,
17 | специфичные для их запуска. После этого, запустив команду `docker-compose up`, мы смогли бы
18 | одномоментно вызвать весь стек приложения.
19 |
20 | Такой вариант проще реализовать, запускать и поддерживать, чем отдельные контейнеры с bash
21 | скриптами, поскольку все изменения всегда хранятся в одном файле конфигурации
22 | docker-compose.yaml. Но тут есть определенные ограничения, т.к. все это применимо только к
23 | запуску контейнеров на одном хосте Docker. Пока не будем беспокоится о моем yaml-файле.
24 | Он вполне рабочий, но это слишком простое приложение, которое я собрал. Давай посмотрим на
25 | лучший пример.
26 |
27 |
28 |
29 | У нас есть приложение от создателей докера, на котором хорошо отрабатывать особенности этой
30 | технологии. Итак, задача приложения собрать голоса пользователей, обработать их, сохранить и
31 | показать результат по требованию. Приложение должно быть шустрое, выдерживать большую
32 | пиковую нагрузку и быть устойчивым к сбоям.
33 |
34 | Согласно этим требованиям разработчики создали приложение. Скорость будет достигаться за
35 | счет использования технологий кэширования, вроде redis, масштабирование достигается за счет
36 | контейнеризации, а устойчивость к сбоям за счет микросервисной архитектуры. Это тестовое
37 | приложение для голосования имеет под собой три логических яруса: фронтенд, бекенд и обработка
38 | данных.
39 |
40 | Приложение для голосования - voting-app - разработано на Python, оно предоставляет веб-страницу
41 | с двумя опциями: Cats и Dogs. После того, как пользователь сделал выбор, voting-app передает эти
42 | данные для обработки в бэкэнд. Приложения voting-app и result-app несут в себе функции
43 | представления данных и взаимодействия с пользователем, другими словами фронтенд. Задача
44 | этих приложений устойчиво отработать под нагрузкой, дав нашим пользователям хороший опыт от
45 | общения с системой - user experience - UX.
46 |
47 | Если бы voting-app пыталось сразу записать данные в реляционную СУБД, вроде Postgres, мы бы
48 | быстро уперлись в ограничение пропускной способности БД. Пока база обрабатывала все запросы,
49 | наш портал example-vote.com был бы недоступным. Мы пойдем другим путем.
50 | Для обеспечения быстрой работы используем временное хранилище данных redis. Благодаря тому,
51 | что его база находится в оперативной памяти, voting-app очень быстро выполнит запрос и вернется
52 | к своему привычному делу - показывать веб-страницу пользователю.
53 |
54 | Итак, на первом этапе все данные стекаются в in-memory cache, реализованный в redis. Далее в
55 | игру вступает третий компонент нашей системы - worker.
56 |
57 | Worker это .net приложение, его функция периодически забирать информацию из кэша, производить
58 | дополнительные действия по ее проверке и подготовке к хранению, а далее отправить этот "пакет"
59 | данных в Postgres на постоянное хранение.
60 |
61 | Реляционная база данных хранит свою информацию в виде таблиц, из-за этого скорость записи у
62 | нее не так высока, как скорость чтения. Result-app демонстрирует результаты голосования,
63 | вычитывая их из БД с вполне с приличной скоростью, а если этого вдруг станет не хватать, то
64 | всегда можно будет подключить redis и к этому процессу.
65 |
66 |
67 |
68 | Это все по архитектуре нашего simple voting application. Я бы сравнил это с фабрикой.
69 |
70 | Кладовщики (python) имеют одну задачу - максимально быстро положить на склад (redis) все
71 | прибывающие материалы (запросы от юзеров). Воркер - это автоматизированная линия, которая
72 | постоянно производит свои товары из материалов (задания для БД из запросов). База данных
73 | Postgres - склад готовой упакованной продукции, которую удобно будет использовать
74 | потребителям. А служба доставки (NodeJS) - доставляет готовые результаты пользователям.
75 |
76 | Как видишь решение наших разработчиков сочетает в себе несколько инструментов, платформ и
77 | технологий. На его примере мы посмотрим, как легко можно настроить стек разнородных
78 | компонентов в Docker.
79 |
80 | На пару минут отложим в сторону все автоматизации вроде services от docker-compose и stacks от
81 | Docker swarm и посмотрим, как мы можем собрать этот стек приложений на едином окружении
82 | Docker, используя сначала обычные команды запуска.
83 |
84 | Мы считаем, что все наши образы уже созданы и доступны в Docker-репозитории.
85 |
86 |
87 |
88 | Давай начнем с уровня данных.
89 | Для запуска используем команду `docker run`.
90 | Начнем с redis.
91 | Команда `docker run -d --name=redis redis`
92 |
93 | Как мы знаем, параметр -d говорит Docker, что контейнер нужно запустить в фоновом режиме.
94 | Также мы указываем имя контейнера redis. Имя контейнера важно, а почему, ты скоро поймешь.
95 |
96 | Далее разворачиваем Postgres DB
97 | Команда `docker run -d --name=db postgres:9.4`
98 |
99 | -d значит тоже самое, что и в предыдущий раз - запуск в бекграунде. Имя для контейнера базы db.
100 |
101 | Дальше очередь фронтенда. Запустим сборщик голосов командой
102 | `docker run -d --name=vote -p 5000:80 voting-app`
103 |
104 | Это приложение веб-сервер, слушает на http порту (#80), мы опубликуем его в хост-системе под
105 | номером 5000. Таким образом трафик полученный на порт 5000 нашей хост-системы будет передан
106 | на порт 80 контейнера vote, этим мы сделаем его доступным из браузера.
107 |
108 | Приложение, показывающие результат result-app разворачиваем командой
109 | `docker run -d --name=result -p 5001:80 result-app`
110 |
111 | Здесь мы аналогично пробрасываем порты для доступности результатов из браузера.
112 |
113 | В конце запустим worker
114 | `docker run -d --name=worker worker`
115 |
116 | Ок, вроде все идет неплохо. Контейнеры запустились. Но проблема в том, что обращение на 5000
117 | порт из браузера - дает нам 500 ошибку.
118 |
119 | Дело в том что мы запустили 5 контейнеров, а не микросервисное приложение. Приложением оно
120 | станет, когда сервисы начнут общаться друг с другом, т.е. у контейнеров будет возможность
121 | коммуницировать. Мы должны связать контейнеры и сказать каждой части приложения с кем им
122 | взаимодействовать. Применительно к voting-app, нужно явно сказать с каким экземпляром redis
123 | ему работать, т.к. redis может быть несколько. Тоже самое с worker, он должен понимать, какой
124 | Postgres ему нужен.
125 |
126 | Как нам это сделать? С помощью links. Link это опция командной строки, позволяющая связать два
127 | контейнера вместе.
128 |
129 | Например веб-сервис voting-app зависит от кэширующего сервиса redis. Когда веб-сервер
130 | запустится этот код будет искать redis на хосте "redis". Но контейнер vote не сможет разрешить это
131 | имя и понять, где находится его redis. Для осведомления voting-app о том, где находится redis мы
132 | используем опцию link при запуске контейнера-голосования.
133 |
134 | Пишется так --link (имя контейнера где живет сервис):(имя по которому будет общаться с этим
135 | контейнером запускаемое приложение).
136 |
137 | В нашем случае `docker run -d --name=vote -p 5000:80 --link redis:redis voting-app`.
138 |
139 | Вот поэтому ранее я говорил, что имена контейнеров важны! Чтобы мы смогли связать требуемые
140 | компоненты.
141 |
142 | Что на самом деле делает --link? Просто вносит статическую запись в /etc/hosts контейнера vote с
143 | привязкой имени redis к текущему внутреннему IP контейнера redis.
144 |
145 | Таким же способом мы связываем контейнер result с контейнером db.
146 |
147 | `docker run -d --name=result -p 5001:80 --link db:db result-app`.
148 |
149 | Как видишь, в коде NodeJS-приложения название базы просто захардкожено. Это не лучшая
150 | практика, но для учебных целей можно.
151 |
152 | Контейнер worker немного отличается от предыдущих, т.к. ему потребуется общаться сразу с двумя
153 | контейнерами: брать данные в redis и отправлять их в db.
154 |
155 | Просто добавим два линка:
156 | `docker run -d --name=worker --link db:db --link redis:redis worker`
157 |
158 | На самом деле link устаревшая конструкция. На смену ей пришли более продвинутые концепции
159 | networks, но для понимания основ конструкция link нам подходит, в любом случае лишним не будет
160 | знать об этой возможности.
161 |
162 |
163 |
164 | Итак, у нас есть проверенные и готовые к использованию команды Docker. Из него будет легко
165 | создать файлы для docker-compose. Начнем с dictionary имен контейнеров. Мы будем создавать его
166 | используя те же названия, что и в командах docker run.
167 |
168 | Теперь мы берем все имена микросервисов и создаем ключ для каждого из них. Затем под
169 | каждым элементом мы указываем, какой использовать образ. Ключ - это будущий контейнер, а
170 | значение - имя образа, которое будет в нем использоваться.
171 |
172 | Также мы использовали дополнительные параметры в командах, а именно в двух командах
173 | публиковали порты. Для этих контейнеров мы укажем проброс соответствующих портов. Создаем
174 | свойство под названием ports и перечисляем все порты, которые мы хотим опубликовать под ним.
175 |
176 | Наконец у нас остались links. Те контейнеры, которые нужно связать друг с другом следует явно
177 | обозначить. За это отвечает свойство links. Это свойство является массивом, таким же как и ports.
178 |
179 | Заметь, если имя службы, к которой идет обращение в коде совпадает с именем контейнера,
180 | например redis или db, то можно указать это имя один раз без двоеточия. Это будет тоже самое,
181 | как если бы указали redis:redis или db:db.
182 |
183 | Мы закончили с нашим файлом конфигурации, и теперь поднять стек на самом деле очень легко.
184 | Делаем это командой `docker-compose up`.
185 |
186 |
187 |
188 | В созданном нами файле docker-compose.yml мы исходили из того, что все образы уже собраны. Из
189 | пяти различных компонентов два известных нам образа redis и postgres уже доступны на
190 | DockerHub.
191 |
192 | Это официальные образы от Redis и Postgres, но остальные три - наше собственное приложение.
193 | Совсем необязательно, чтобы они были уже созданы и записаны в какой-то докер-репозиторий.
194 | Если мы хотим проинструктировать Docker инициировать процесс сборки образа вместо
195 | скачивания уже созданного из репозитория, мы можем поменять параметр image на build, указав
196 | местоположение каталога, который содержит код приложения и Dockerfile с инструкциями по
197 | сборке образа.
198 |
199 | В этом примере у приложения для голосования весь код лежит в папке с именем vote, также она
200 | содержит Dockerfile. Итак, когда мы запустим команду `docker-compose up`, она сначала соберет
201 | образ, даст ему временное имя, а затем будут использовать этот образы для запуска контейнера с
202 | использованием указанных в файле параметров. Аналогичным образом будут созданы две
203 | оставшиеся службы: образы будут собраны из соответствующих папок и запущены их контейнеры
204 |
205 |
206 |
207 | Теперь мы рассмотрим разные версии файла docker-compose. Это важно, потому что мы постоянно
208 | сталкиваемся с разными docker-compose файлами в разных форматах. Возникает вопрос, почему в
209 | разных местах они выглядят по-разному?
210 | Docker-compose с течением времени развивался и сейчас поддерживает гораздо больше
211 | возможностей, чем вначале. Вот, например, урезанная версия файла docker-compose, которую мы
212 | использовали ранее.
213 |
214 | Фактически это ранняя версия docker-compose, которая называется версия 1. У ней есть ряд
215 | ограничений, например, невозможно развернуть контейнеры в другой сети, отличной от мостовой
216 | сети по умолчанию. Также нет возможности указать, что запуск одного контейнера зависит от
217 | запуска другого. Например, наш контейнер базы данных должен появиться первым, и только после
218 | этого должно быть запущено приложение для голосования. Мы не можем указать это в версии 1
219 | файла docker-compose.
220 |
221 | Этот функционал стал поддерживаться только с версией 2 и выше. С версией 2 также немного
222 | изменился и формат файла. Мы больше не указываем информацию о стеке напрямую, как раньше.
223 | Все это стало инкапсулировано в раздел services. Поэтому нам нужно создать свойство с именем
224 | services в корневом уровне yml файла, а затем переместить все описания контейнеров в этот раздел
225 | служб. Чтобы мы по-прежнему могли использовать эту же команду `docker-compose up` для
226 | вызова своего стека приложений, нужно явно сообщить docker-compose, какую версию файла мы
227 | здесь используем. Мы свободно можем использовать версию 1 или версию 2 в зависимости от
228 | своих потребностей. Итак, чтобы все это работало, в первой строчке мы указываем, как
229 | docker-compose разбирать форматирование. Используется параметр version: и указание версии.
230 |
231 | В этом случае цифра 2 после двоеточия сразу скажет docker-compose объединить контейнеры в
232 | единую мостовую сеть, а затем использовать ссылки для связи между контейнерами, как мы это
233 | делали явно в первой версии нашего файла.
234 |
235 | Это еще одно отличие первой версии от второй, что контейнеры сразу могут связываться друг с
236 | другом, используя имена, заданные под параметром services. Т.е. во второй версии docker-compose параметр links больше не
237 | нужен. Мы можем просто избавиться от всех ссылок, которые были
238 | созданы, при конвертации docker-compose файла из версии 1 в версию 2.
239 |
240 | И, наконец, версия 2 также вводит функцию зависимостей для запуска, если мы хотим указать
241 | порядок создания контейнеров. Например, веб-приложение для голосования зависит от службы
242 | redis. Таким образом, нам необходимо убедиться, что контейнер redis запускается первым, и
243 | только после этого запускается веб-приложение для голосования. Мы можем добавить свойство
244 | depends_on, в приложение для голосования и указать, что оно зависит от redis.
245 |
246 | Теперь версия 3. На сегодняшний день последняя версия 3.8. Ее структура сходна с версией 2.
247 | Вверху описание версии, далее идет раздел services, в который мы также помещаете все свои
248 | контейнеры, как и в версии 2. Существенное отличие в 3 версии - ее поддержка оркестрации с
249 | помощью Docker swarm и специфичных возможностей для совместной работы нескольких хостов.
250 |
251 | В ней некоторые параметры были удалены, и многие добавлены. Увидеть подробности ты можешь
252 | в разделе документации на сайте docker, поискав по слову compose. В следующих лекциях мы
253 | взглянем на версию 3 более подробно, когда обсудим Docker Stacks.
254 |
255 |
256 |
257 | Сейчас давай поговорим о сетях в docker-compose касательно нашего приложения. До сих пор мы
258 | просто развертывали все контейнеры в мостовой сети по умолчанию. Хорошей практикой является
259 | разделить трафик из разных источников. Давай немного изменим архитектуру нашего
260 | развертывания.
261 |
262 | Например, мы решили отделить трафик, генерируемый пользователями, от внутреннего трафика
263 | приложений. Для этого мы создаем внешнюю сеть, предназначенную для трафика от
264 | пользователей, и внутреннюю сеть, предназначенную для общения между приложениями.
265 |
266 | Фронтенд и бэкенд. Сетью фронтенда связываем приложения, ориентированные на пользователя,
267 | это приложение для голосования и для результатов. Бэкендом свяжем внутренние компоненты:
268 | redis, postgres и worker. Все это мы можем занести в наш файл docker-compose.yml
269 |
270 | Обрати внимание, что я вырезал раздел портов для простоты, они все еще там, но просто не
271 | показаны на экране.
272 |
273 | Первое, что нам нужно сделать, если мы будем использовать networks, - это определить какие
274 | именно сети мы собираемся использовать в этом развертывании. У нас есть две: внешняя и
275 | внутренняя сети. Поэтому создадим новое свойство, называемое networks, на уровне корня yaml
276 | документа, а не в services. В этом свойстве мы разместим нашу карту сетей. Мы планируем
277 | использовать эти сети во всех объявленных службах. Таким образом нам придется их явно
278 | объявить при помощи свойства networks уже внутри имени службы, к каким сетям должен быть
279 | подключен этот контейнер.
280 |
281 | В данный момент мы указали, что result подключен к сети frontend и backend. потому что это
282 | приложение берет данные из внутренней сети и отдает их во внешнюю. Так же и для vote. К каким
283 | сетям будут подключены службы redis и dB?
284 |
285 | Это только backend, т.к. эти приложения не взаимодействуют с пользователем. В отличие от
286 | интерфейсных приложений, таких как приложение для голосования и результатов, которые
287 | необходимо подключить как к фронтенду, так и к бэкенду. Мы также должны добавить раздел
288 | networks для воркера, чтобы его контейнер был добавлен во внутреннюю сеть, здесь просто не
289 | хватило на него места.
290 |
291 |
292 |
293 | Теперь, когда мы разобрали эти файлы docker-compose переходим к практике, чтобы
294 | потренироваться в составлении подобных yaml файлов. Но перед этим я хочу показать тебе
295 | несколько основных команд Docker Compose.
296 |
297 | `docker-compose up -d`
298 | Разворачивает стек из файла docker-compose.yml текущей директории.
299 |
300 | `docker-compose down`
301 | Останавливает стек и удаляет все контейнеры и сети.
302 |
303 | `docker-compose ps`
304 | Покажет контейнеры, за которые Docker Compose несет ответственность.
305 |
306 | `docker-compose logs`
307 | Общий пул логов поднятого стека Docker Compose.
308 |
309 | `docker-compose up --scale vote=3`
310 | Управление количеством реплик определенной службы.
311 |
--------------------------------------------------------------------------------