{"id":20408865,"url":"https://github.com/dockersamples/newsletter-signup","last_synced_at":"2025-10-29T17:40:39.289Z","repository":{"id":43331619,"uuid":"92285527","full_name":"dockersamples/newsletter-signup","owner":"dockersamples","description":"Newsletter Sign Up - a .NET Framework app using Docker containers on Windows","archived":false,"fork":false,"pushed_at":"2024-10-26T09:52:00.000Z","size":2113,"stargazers_count":29,"open_issues_count":0,"forks_count":16,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-11T19:09:32.652Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dockersamples.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-24T11:35:47.000Z","updated_at":"2025-04-04T04:02:03.000Z","dependencies_parsed_at":"2022-07-12T18:18:56.723Z","dependency_job_id":null,"html_url":"https://github.com/dockersamples/newsletter-signup","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dockersamples%2Fnewsletter-signup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dockersamples%2Fnewsletter-signup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dockersamples%2Fnewsletter-signup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dockersamples%2Fnewsletter-signup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dockersamples","download_url":"https://codeload.github.com/dockersamples/newsletter-signup/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248590196,"owners_count":21129766,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T05:37:31.431Z","updated_at":"2025-10-29T17:40:39.217Z","avatar_url":"https://github.com/dockersamples.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Newsletter Sign Up\n\nA .NET Framework app using Docker containers on Windows. The app lets users sign up to a fictional newsletter:\n\n![SignUp homepage](img/signup-homepage.png)\n\n## Architecture\n\nThis is a distributed application, running across multiple containers (defined in [docker-compose.yml](app/docker-compose.yml)):\n\n- `db` - [SQL Server Express](https://store.docker.com/images/mssql-server-windows-express), used to store prospect details\n- `message-queue` - [NATS](https://store.docker.com/images/nats) message queue, used for event publishing and subscribing\n- `web` - ASP.NET WebForms application, front end for prospects to sign up\n- `save-handler` - .NET console app, listens for prospect events and saves data to `db`\n- `index-handler` - .NET console app, listens for prospect events and saves data to `elasticsearch`\n- `elasticsearch` - [Elasticsearch](https://cloud.docker.com/swarm/sixeyed/repository/docker/sixeyed/elasticsearch/general) document database, used for reporting\n- `kibana` - [Kibana](https://cloud.docker.com/swarm/sixeyed/repository/docker/sixeyed/kibana/general) front end to `elasticsearch`, used for self-service analytics\n\n## Pre-reqs\n\nThese are all Windows images, so you'll need Windows 10 or Windows Server 2016, and [Docker for Windows](https://store.docker.com/editions/community/docker-ce-desktop-windows) installed. \n\n\u003e [Docker secrets](https://docs.docker.com/engine/swarm/secrets/) and [multi-stage builds](https://docs.docker.com/engine/userguide/eng-image/multistage-build/) are used too, so you'll need at least version `17.06` of Docker.\n\n\n## Build - *Optional\n\nAll the images used in the sample are available in public image repositories on Docker Cloud. You don't need to build from source, but if you want to you can clone this repo, and from the root directory use Docker Compose to build the app:\n\n```\ndocker-compose `\n -f .\\app\\docker-compose.yml `\n -f .\\app\\docker-compose.build.yml `\n build \n```\n\nYou'll see that Docker compiles the .NET apps before packaging them into images. That's the multi-stage build using an [image from Docker Cloud with MSBuild installed](https://cloud.docker.com/swarm/sixeyed/repository/docker/sixeyed/msbuild/general), so you don't need Visual Studio - or even .NET - installed on your machine to build this app from source code.\n\n\u003e The build images use [Windows Server Core](https://store.docker.com/images/windowsservercore), which is a large base image. The first time you run the build it will pull any missing images, which could take a while.\n\nWhen the build completes, run the app - you can either run in swarm mode, or on a standalone Docker instance with Docker Compose.\n\n## Running the App in Swarm Mode\n\nThe app is configured to use secrets in swarm mode, so the database credentials are securely stored and distributed by the swarm. The only place where the sensitive data can be read is inside the containers, and the application code reads that configuration from the secret files.\n\nYou can turn your laptop into a single-node swarm:\n\n```\ndocker swarm init\n```\n\nAnd now you can create secrets. There's a [script in the repo](app/create-secrets.ps1) that does that for you, but it just creates secrets using the contents of text files:\n\n```\ncd app\n.\\create-secrets.ps1\n```\n\nThe [docker-stack.yml](app/docker-stack.yml) file contains the whole application configuration, including the secrets for the web app, console app and database. You can deploy the whole distributed application as a stack:\n\n```\ndocker stack deploy --compose-file docker-stack.yml signup\n```\n\nDocker will create all the services, and make the secrets available to the relevant containers. \n\n### Running the App with Compose\n\nIf you're not running Docker in swarm mode, you can still run the app with Docker Compose. You lose the secure secrets, but you still have the same functionality:\n\n```\ndocker-compose `\n -f .\\app\\docker-compose.yml `\n -f .\\app\\docker-compose.local.yml up -d\n```\n\n\u003e This approach uses unencrypted text files instead of secrets, so it's only suitable for dev environments. \n\n## Try the App\n\nIf you've deployed the app to a swarm, just browse to the IP address of the swarm host - the web application is mapped to port 80 on the host.\n\nIf you've deployed using compose, you'll need the IP address of the `web` container to open the site. In PowerShell, this grabs the IP address of the container and launches your browser:\n\n```\n$ip = docker inspect --format '{{ .NetworkSettings.Networks.nat.IPAddress }}' app_web_1\nstart \"http://$ip\"\n```\n\nThe application functionality is the same however you run it, because the stack and the local compose deployment use the same images and the same [core compose file](app/docker-compose.yml).\n\nSave your details and you can check the logs of the message handler services (or containers) to see the events being consumed and processed. You can connect to the SQL Server container from SSMS (using the IP address of the `db` container and the credentials in [db-credentials.env](app/db-credentials.env)), or run a command in the container to see the data:\n\n```\ndocker exec app_db_1 `\n powershell \"Invoke-SqlCmd -Query 'SELECT * FROM Prospects' -Database SignUp\"\n```\n\nYou can browse to Kibana too, to see how the data is saved in the reporting database:\n\n```\n$ip = docker inspect --format '{{ .NetworkSettings.Networks.nat.IPAddress }}' app_kibana_1\nstart \"http://$($ip):5601\"\n```\n\nThe index is called `prospects`, and you'll see that the fields are pre-populated from Elasticsearch with the data you've added:\n\n![SignUp Kibana](img/signup-kibana.png)\n\n\n## Run End-to-End Tests\n\nThere's also an [integration test suite](src/SignUp/SignUp.EndToEndTests/ProspectSignUp.feature) in the source code, which uses [SpecFlow](http://specflow.org/), [Selenium](http://www.seleniumhq.org/) and [SimpleBrowser](https://github.com/SimpleBrowserDotNet/SimpleBrowser). Those tests run a headless web browser which connects to the site and completes the sign up form with a set of known data. Then for each case it checks the data exists in SQL Server.\n\nBuild the tests from the root path of the repo:\n\n```\ndocker build -t dockersamples/signup-e2e-tests -f docker\\e2e-tests\\Dockerfile .\n```\n\nThe output is an image which has [NUnit Console](https://github.com/nunit/docs/wiki/Console-Command-Line) installed, along with the compiled test suite. Running the test suite in a container means it can access the `web` and `db` app containers by name, using service discovery built into Docker.\n\nRun the tests and you'll see all 26 pass:\n\n```\ndocker run --env-file app\\db-credentials.env --name e2e-tests dockersamples/signup-e2e-tests\n...\nTest Run Summary\n  Overall result: Passed\n  Test Count: 26, Passed: 26, Failed: 0, Warnings: 0, Inconclusive: 0, Skipped: 0\n  Start time: 2017-05-24 12:34:00Z\n    End time: 2017-05-24 12:34:07Z\n    Duration: 7.349 seconds\n\nResults (nunit3) saved as TestResult.xml\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdockersamples%2Fnewsletter-signup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdockersamples%2Fnewsletter-signup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdockersamples%2Fnewsletter-signup/lists"}