├── 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 | environment variables 4 | 5 | Начнем с нашего простого приложения, показывающее ракеты. Оно написано на python. Взгляни на 6 | этот участок кода. Он создает веб-сервер, который демонстрирует веб-страницу с ракетой. Если ты 7 | посмотришь внимательно, ты найдешь строку, которая определяет размер ракеты как small. 8 | 9 | В данный момент все это работает прекрасно. Однако, если ты решишь изменить размер ракеты в 10 | будущем, то придется менять код приложения. Лучшая практика в таком случае вынести 11 | информацию из кода приложения в переменную окружения с именем ROCKET_SIZE. 12 | 13 | environment variables 14 | 15 | Внесем изменения в код. Теперь при запуске приложения установим переменную окружения 16 | ROCKET_SIZE в желаемое значение при помощи команды `export ROCKET_SIZE=big; python3 app.py` и 17 | запустим приложение. Как видишь такой подход может избавить нас от сборки отдельного билда 18 | приложения под каждый размер ракеты. 19 | 20 | environment variables in docker 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 | docker inspect 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 | whalesay say hello 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 | docker swarm 9 | 10 | С Docker Swarm ты можешь собрать несколько докер-хостов в единый кластер, который будет 11 | согласованно работать над твоими задачами. Кластер займется распределением служб или 12 | экземпляров приложений на отдельные хосты, тем самым обеспечит высокую доступность и 13 | балансировку нагрузки между различными системами и оборудованием. 14 | 15 | docker swarm 16 | 17 | Для начала тебе потребуется одна или несколько машин с установленным на них Docker. После 18 | этого нужно определиться, какой из этих хостов будет использоваться в роли менеджера или 19 | мастера. Остальные хосты станут слейвами или воркерами. 20 | 21 | Затем запустим команду `docker swarm init` на менеджере для инициализации менеджера swarm. 22 | 23 | В выводе команды будет представлена команда, которую нужно запустить на воркерах, для того, 24 | чтобы рабочие экземпляры swarm смогли присоединиться к менеджеру в кластере. После 25 | присоединения к swarm рабочие хосты станут называться нодами, и теперь мы готовы создавать 26 | службы и развертывать их в кластере swarm. 27 | 28 | docker service 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 | docker run alpine 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 | enter inside a container 38 | 39 | ```shell 40 | hostname 41 | ``` 42 | 43 | get docker id of a container 44 | 45 | Давай посмотрим на релизную информацию этой ОС 46 | 47 | ```shell 48 | cat /etc/*rel* 49 | ``` 50 | 51 | get release info 52 | 53 | Посмотрим на список работающий контейнеров 54 | 55 | ```docker 56 | docker ps 57 | ``` 58 | 59 | docker ps 60 | 61 | Запустим контейнер в фоновом режиме `-d` , чтобы открепить от него консоль и займем контейнер выполнением 62 | процесса `sleep` 63 | 64 | ```docker 65 | docker run -d alpine sleep 15 66 | ``` 67 | 68 | docker ps after running alpine 69 | 70 | Тебе потребуется команда, чтобы увидить все контейнеры, которые присутствуют у тебя на хосте. 71 | Как работающие, так и уже выполненные/остановленные. 72 | 73 | ```docker 74 | docker ps -a 75 | ``` 76 | 77 | all containers 78 | 79 | Запустим alpine в detached mode на 1000 секунд 80 | 81 | ```docker 82 | docker run -d alpine sleep 1000 83 | ``` 84 | 85 | Чтобы прервать работу контейнера ("Убить контейнер") 86 | 87 | sleep 1000 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 | docker rm 104 | 105 | Теперь переходим к образам 106 | 107 | ```docker 108 | docker images 109 | ``` 110 | 111 | docker images 112 | 113 | Для удаления контейнеров есть команда 114 | 115 | ```docker 116 | docker rmi alpine 117 | ``` 118 | 119 | docker rmi 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 | docker rmi 171 | 172 | Помогают в решении пролем команды `docker inspect` `cocker logs` 173 | -------------------------------------------------------------------------------- /8_container_orchestration/8_1_orchestration/orchestration.md: -------------------------------------------------------------------------------- 1 | # Оркестрация 2 | 3 | Привет и добро пожаловать на лекцию по оркестрации контейнеров. Здесь мы поговорим о том, 4 | как быть, если одного докер-хоста по каким-то причинам недостаточно для разворачивания 5 | проекта, с какими трудностями сталкиваются и как их преодолевают. 6 | 7 | orchestration 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 | orchestration 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 | orchestration technologies 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 | default networks 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 | user networks 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 | inspect network 62 | 63 | Для того, чтобы увидеть настройки сети и IP-адрес, назначенный существующему контейнеру, 64 | запустим команду `docker inspect` с названием контейнера или его ID. Там, в разделе 65 | NetworkSettings -> Networks мы можем увидеть тип сети, к которой контейнер привязан, его 66 | внутренний IP-адрес, Mac-адрес. 67 | 68 | embedded dns 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 | yaml 12 | 13 | Здесь быстрое сравнение образцов одинаковых данных в трех разных форматах. Левый это XML, 14 | где мы представили список серверов и информацию о них. Те же данные представлены в JSON 15 | формате посередине. И, наконец, YAML формат справа. Посмотри внимательно на форматы и 16 | сравни их. 17 | 18 | yaml 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 | yaml spaces 36 | 37 | Теперь взглянем внимательнее на пробелы в YAML. Здесь у нас dictionary, представляющий 38 | пищевую ценность банана. Показаны общее количество калорий, жира, углеводов и белка. Обрати 39 | внимание, количество пробелов перед каждым элементом определяет, что эти пары 40 | "ключ-значение" относятся к банану. Что произойдет, если добавить дополнительные пробелы для 41 | fat, carbs и protein? 42 | 43 | Они попадут в категорию калорий, т.е. станут свойствами калорий, в чем нет никакого смысла. Еще 44 | это приведет к синтаксической ошибке, которая сообщит, что сопоставление значений здесь 45 | недопустимо, поскольку у ключа calories есть уже значение 102. Ты можешь присвоить ключу - 46 | значение, или установить его как название для низлежащего объекта, но только что-то одно. 47 | Количество пробелов перед каждым свойством является ключевым в YAML. Убедись в 48 | правильности расстановки пробелов, чтобы данные были представлены как предполагалось. 49 | 50 | yaml 51 | 52 | Усложним задачу. Давай создадим list, содержащий dictionaries. В этом случае у нас есть list 53 | фруктов - fruits. Его элементы банан и яблоко. Каждый из этих элементов представляет из себя 54 | dictionary, в котором содержится пищевая ценность. 55 | 56 | data types yaml 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 | yaml specials 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 | kubernetes 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 | claster 58 | 59 | Нода это машина, физическая или виртуальная, на которой установлен Kubernetes. Воркер нода, это 60 | узел, на котором Kubernetes будет запускать контейнеры с полезной нагрузкой. Раньше они 61 | назывались миньонами. Услышав этот термин имей в виду, что это синонимы. Что случится, если 62 | нода выйдет из строя? 63 | 64 | Очевидно, что наше приложение упадет. Выходит, нам нужно иметь больше одной ноды. Кластер - 65 | это набор сгруппированных вместе узлов. Таким образом, даже если один узел падает, наше 66 | приложение по-прежнему доступно для пользователей. Более того, наличие нескольких нод также 67 | помогает в распределении нагрузки. 68 | 69 | master 70 | 71 | Ок, теперь у нас есть кластер, но кто будет отвечать за его управление? Где будет храниться 72 | информация о членах кластера? Как нам узнать о событиях, происходящих на нодах? А когда нода 73 | выйдет из строя, как перенести рабочую нагрузку с упавшей ноды на исправную? 74 | 75 | Вот здесь появляется мастер, или как теперь его политкорректно называют controlplane. Мастер 76 | это еще одна нода, член кластера Kubernetes, сконфигурированная как мастер. У нее особые 77 | функции: наблюдать за состоянием других нод и быть ответственной за оркестрацию контейнеров 78 | на воркер-нодах. 79 | 80 | components 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 | kubectl 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 | processes in container 4 | 5 | Начнем с простого сценария. Предположим, что мы запустили контейнер с образом ubuntu. Когда 6 | мы ввели команду `docker run ubuntu`, Docker запустил экземпляр образа ubuntu и немедленно 7 | сделал выход из контейнера. 8 | 9 | Если сейчас посмотреть список работающих контейнеров, то мы не увидим их. Если же запустить 10 | `docker ps -a`, тем самым запросив список всех контейнеров на хосте, мы увидим наш новый 11 | контейнер, он будет остановлен со статусом exited. Почему это не работает как виртуальная 12 | машина? 13 | 14 | processes in container 15 | 16 | Как мы уже говорили, контейнеры не предназначены для размещения операционных систем. 17 | 18 | Они подходят для некоторых процессов вроде запуска веб-сервера, базы данных или 19 | аналитической задачи. Когда задача завершена, контейнер останавливается. Жизнь в нем 20 | поддерживает работающий внутри процесс. Т.е. если веб-сервер, или база данных, или другой 21 | запущенный процесс внутри контейнера остановится или скрашится, то контейнер немедленно 22 | выйдет. Итак, что определяет, какой процесс будет запущен в контейнере? 23 | 24 | command 25 | 26 | Если посмотреть на Dockerfile такого популярного приложения как nginx ты увидишь инструкцию 27 | CMD. Эта инструкция определяет команду, которая будет запускаться в контейнере при запуске 28 | его из образа. Это команда nginx. Для официального образа MySQL в Dockerfile будет команда 29 | mysqld. 30 | 31 | os inside a container 32 | 33 | Ранее мы пытались запустить контейнер с пустой ОС Ubuntu. Посмотрим на Dockerfile этого образа 34 | и мы увидим, что команда по умолчанию там bash. Но как мы знаем bash это не совсем такой 35 | процесс, вроде веб-сервера или базы данных. Это оболочка, которая ждет ввода с терминала и, 36 | если если она не может найти терминал, она завершается. Когда мы запускали контейнер с Ubuntu 37 | ранее, Docker создавал контейнер из образа Ubuntu и запускал программу bash по умолчанию. 38 | Терминал к контейнеру при запуске Docker не подключал. 39 | 40 | Таким образом, программа bash не находила терминал и завершала работу. 41 | А поскольку процесс, который был запущен при создании контейнера, завершался, то и контейнер 42 | также останавливался. Как нам указать другую команду при старте контейнера? 43 | 44 | sleep 5 45 | 46 | Один из вариантов - добавить нужную команду к `docker run` и таким образом переопределить 47 | команду по умолчанию, указанную в образе. 48 | 49 | В этом случае мы выполним: 50 | `docker run Ubuntu с командой sleep 5` в качестве дополнительного параметра. 51 | 52 | Теперь, когда контейнер стартует, будет запущена команда sleep. Она будет выполняться 5 секунд, 53 | после чего удачно завершится, что соответственно и завершит выполнение контейнера. Как 54 | сделать эти изменения постоянными? Скажем, тебе нужно всегда запускать команду sleep. 55 | 56 | os inside a container 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 | entrypoint 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 | commands and entrypoint 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 | registry 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 | image 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 | private registry 67 | 68 | С точки зрения Docker, для запуска контейнера с использованием образа из приватного реджистри 69 | cначала нужно выполнить аутентификацию в свой частный реестр с помощью команды `docker 70 | login` и ввода своих учетных данных. После этого данные для входа сохраняются на докер-хосте и 71 | при взаимодействии с этим реджистри будут использованы. 72 | 73 | Для запуска приложения используй название частного реджистри как часть имени образа, как ты 74 | видишь на экране. Если ты попробуешь обратиться за образом в частный реджистри, не войдя в 75 | него, то получишь сообщение, что образ не может быть найден. Поэтому не забудь всегда входить 76 | в систему, прежде чем пушить или пуллить в частный реджистри. 77 | 78 | private registry deploy 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 | how to create docker image 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 | how to create docker image 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 | docker layers 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 | docker build 92 | 93 | Во время сборки образа команда `docker build` выводит все шаги, которые она делает, какие 94 | команды запускает и их результат. Все слои кэшируются, поэтому слоеная архитектура помогает 95 | тебе как в случае ошибок при сборке, так и при проведении повторной сборки образа. Тебе не 96 | нужно начинать все сначала - Docker перестроит только те слои, в которые были внесены 97 | изменения. 98 | 99 | У каждого слоя есть свой хеш, по которому Docker отслеживает их уникальность 100 | 101 | build fail 102 | 103 | Например, при сборке на четвертом шаге произошел сбой. Мы разобрались и уточнили причину 104 | сбоя. Теперь мы перезапустим сборку и увидим, что старые три слоя были переиспользованы из 105 | кэша, а фактическое исполнение команд Docker начал только с четвертого шага. 106 | 107 | Тоже самое будет, если ты изменишь одну из команд - низлежащие под ней слои (т.е. слои, 108 | которые были выполнены до этой инструкции) не будут затронуты, но будет перестроен слой 109 | измененной команды и все слои после нее. Эти новые слои также добавятся в общий кэш докера. 110 | Это позволяет создавать образы быстрее, тебе не нужно ждать команды, которые уже до этого 111 | были выполнены. 112 | 113 | Это очень полезно при обновлении исходного кода приложения. Обычно исходный код в 114 | контейнере подвергается изменению гораздо чаще, чем библиотеки и зависимости, поэтому 115 | копирование файлов приложения находится обычно в конце Dockerfile 116 | 117 | what can be containerized 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 | docker engine 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 | containerization 51 | 52 | Теперь давай попробуем разобраться, как именно в Docker контейнеризирует приложения чуть 53 | ниже уровнем, что называется "под капотом". 54 | 55 | В случае Linux Docker использует пространство имен (namespaces linux) для изоляции 56 | идентификаторов процессов рабочего пространства, подключения к сети, системы разделения 57 | времени Unix. Процессы контейнера выполняются в их собственном пространстве имен, тем 58 | самым обеспечивая изоляцию с другими процессами. Если тебе не очень ясно, это нормально. 59 | Когда я впервые об этом услышал, я ничего не понял, поскольку раньше не встречался с 60 | namespaces. 61 | 62 | namespace 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 | cgroups 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 | docker ps 34 | 35 | Каждый контейнер получает случайным образом выбранный ID и случайное имя, если оно не было указано явно при создании. 36 | 37 | Весь список контейнеров, и запущенных и нет, показывает команда docker ps -a 38 | 39 | ```docker 40 | docker ps -a 41 | ``` 42 | 43 | docker ps -a 44 | 45 | Как ты видишь, в системе 2 контейнера. 46 | Контейнер №1 работает, а №2 - нет. 47 | 48 | 3. Как остановить работающий контейнер? 49 | 50 | Используй docker stop вместе с id контейнера или его именем. 51 | 52 | ```docker 53 | docker stop 54 | ``` 55 | 56 | docker stop 57 | 58 | Если ты не уверен в имени или id лучше для начала вызови docker ps 59 | 60 | docker ps 61 | 62 | Еще раз резюмируем: 63 | 64 | + docker ps - это запущенные контейнеры 65 | + docker ps -a - это все, которые есть на хосте (работающие и нет) 66 | 67 | docker container stopped 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 | docker rm 86 | 87 | Для проверки запустим docker ps и посмотримверно ли все удалилось. 88 | 89 | docker ps after rm 90 | 91 | Как видишь, его больше нет в нашей системе. 92 | 93 | 5. А что со сканенным образом nginx, который докер скачал в начале? 94 | 95 | Он нам тоже не нужен. Мы не собираемся его больше использовать, нужно удалить этот образ. Но для начала давай посмотрим 96 | на список образов, представленных на нашем докер-хосте. 97 | 98 | Комадна docker images покажет все доступные на хосте образы, их id, теги и размер. 99 | 100 | ```docker 101 | docker images 102 | ``` 103 | 104 | docker images 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 | docker rmi 126 | 127 | 7. Ранее я запустил команду docker run и она скачала образ redis, поскольку не нашла его локально на хосте. А что, если 128 | мы просто хотим скачать образ и сохранить? Например для того, чтобы потом быстро запустить redis не ожидая пока его 129 | образ запуллиться из репозитория. 130 | 131 | В этом нам поможет команда docker pull 132 | 133 | ```docker 134 | docker pull redis 135 | ``` 136 | 137 | docker pull 138 | 139 | Которая просто скачает образ, но не будет его запускать. 140 | 141 | Как видишь, найдя локально image, docker run не идет за ним в репозиторий. 142 | 143 | docker run redis 144 | 145 | ## Особенности контейнеров 146 | 147 | Если мы запустим контейнер из образа Ubuntu при помощи команды 148 | 149 | ```docker 150 | docker run ubuntu 151 | ``` 152 | 153 | Это запустит экземпляр ubuntu и немедленно выйдет из него. 154 | 155 | docker run ubuntu 156 | 157 | При просмотре работающих контейнеров мы не его не увидим 158 | 159 | docker ps after run ubuntu 160 | 161 | Но если посмотреть всписок всех контейнеров, находящихся на хосте, включая остановленные, обнаружатся контейнеры с 162 | состоянием exited 163 | 164 | docker ps after run ubuntu 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 | docker ps -a ubuntu status up 208 | 209 | Внутри него выполняется команда sleep 500. Я хочу увидеть содержимое файла внутри контейнера. Как мне это сделать? 210 | 211 | Используем docker exec для выполнения команд на работающем контейнере: 212 | 213 | ```docker 214 | docker exec clever_morse cat /etc/hosts 215 | ``` 216 | 217 | docker exec 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 | rotorocloud web app 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 | rotorocloud web app detached mode 263 | 264 | Пишется как деш-ди. Это запустит контейнер в фоновом режиме и ты сразу же сможешь взаимодействовать со своей оболочкой. 265 | 266 | Контейнер продолжит свое выполнение. Чтобы проверить это ты можешь запустить docker ps 267 | 268 | В любой момент ты можешь прикрепить контейнер к консоли запустив команду docker attach с указанием id или имени 269 | контейнера 270 | 271 | docker attach 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 | stdin 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 | stdin 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 | stdin 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 | stdin 142 | 143 | Команда `docker ps` хорошо подходит для быстрого сбора основные деталей о контейнерах в нашей 144 | системе. Таких как имена, ID и т.д. Но периодически нам будет требоваться развернутая 145 | информация о каком-то контейнере. В подобных случаях нас выручит команда `docker inspect`, она 146 | запускается с именем или ID контейнера. 147 | 148 | Она вернет нам детальную картину этого контейнера в JSON формате. Его состояние, что 149 | смонтировано, как сконфигурировано, настройка сети и т.д. Не забудь про нее, когда тебе нужно 150 | будет узнать детали запущенного и забытого кем-то контейнера или в похожей задаче. 151 | 152 | stdin 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 | filesystem 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 | storage layers 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 | layered architecture 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 | copy on write 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 | volumes 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 | storage drivers 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 | docker-compose 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 | voting app 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 | voting application 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 | voting application 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 | docker compose 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 | docker compose build 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 | docker compose versions 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 | voting application 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 | docker compose commands 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 | --------------------------------------------------------------------------------